diff --git a/src/Bootstrappers/QueueTenancyBootstrapper.php b/src/Bootstrappers/QueueTenancyBootstrapper.php index 6a88f701..28edfdc3 100644 --- a/src/Bootstrappers/QueueTenancyBootstrapper.php +++ b/src/Bootstrappers/QueueTenancyBootstrapper.php @@ -7,6 +7,7 @@ namespace Stancl\Tenancy\Bootstrappers; use Illuminate\Support\Str; use Illuminate\Config\Repository; use Illuminate\Queue\QueueManager; +use ReflectionClass; use Stancl\Tenancy\Contracts\Tenant; use Illuminate\Queue\Events\JobFailed; use Illuminate\Queue\Events\JobProcessed; @@ -16,6 +17,8 @@ use Illuminate\Queue\Events\JobRetryRequested; use Illuminate\Support\Testing\Fakes\QueueFake; use Illuminate\Contracts\Foundation\Application; use Stancl\Tenancy\Contracts\TenancyBootstrapper; +use Stancl\Tenancy\Exceptions\TenancyNotInitializedException; +use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedById; class QueueTenancyBootstrapper implements TenancyBootstrapper { @@ -58,7 +61,7 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper $dispatcher->listen(JobProcessing::class, function ($event) use (&$previousTenant) { $previousTenant = tenant(); - static::initializeTenancyForQueue($event->job->payload()['tenant_id'] ?? null); + static::initializeTenancyForQueue($event); }); if (Str::startsWith(app()->version(), '8')) { @@ -66,7 +69,7 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper $dispatcher->listen(JobRetryRequested::class, function ($event) use (&$previousTenant) { $previousTenant = tenant(); - static::initializeTenancyForQueue($event->payload()['tenant_id'] ?? null); + static::initializeTenancyForQueue($event); }); } @@ -81,8 +84,11 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper $dispatcher->listen(JobFailed::class, $revertToPreviousState); // artisan('queue:work') which fails } - protected static function initializeTenancyForQueue($tenantId) + protected static function initializeTenancyForQueue($event) { + $tenantId = $event->payload()['tenant_id'] ?? null; + + if (! $tenantId) { // The job is not tenant-aware if (tenancy()->initialized) { @@ -99,7 +105,11 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper tenancy()->end(); } - tenancy()->initialize(tenancy()->find($tenantId)); + try { + tenancy()->initialize($tenantId); + } catch (TenantCouldNotBeIdentifiedById $e) { + static::handleTenantCouldNotBeFound($event->job, $e); + } return; } @@ -114,7 +124,11 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper // Tenancy was either not initialized, or initialized for a different tenant. // Therefore, we initialize it for the correct tenant. - tenancy()->initialize(tenancy()->find($tenantId)); + try { + tenancy()->initialize($tenantId); + } catch (TenantCouldNotBeIdentifiedById $e) { + static::handleTenantCouldNotBeFound($event->job, $e); + } } protected static function revertToPreviousState($event, &$previousTenant) @@ -148,6 +162,25 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper } } + protected static function handleTenantCouldNotBeFound($job, \Throwable $e) + { + $class = $job->resolveName(); + + try { + $shouldDelete = (new ReflectionClass($class)) + ->getDefaultProperties()['deleteWhenCannotIdentify'] ?? false; + } catch (\Throwable $e) { + $shouldDelete = false; + } + + if ($shouldDelete) { + return $job->delete(); + } + + return $job->fail($e); + + } + public function bootstrap(Tenant $tenant) { // diff --git a/tests/QueueTest.php b/tests/QueueTest.php index afe64fea..3695eb43 100644 --- a/tests/QueueTest.php +++ b/tests/QueueTest.php @@ -244,6 +244,30 @@ class QueueTest extends TestCase $this->assertSame('The current tenant id is: acme', $this->valuestore->get('tenant_id')); } + + /** @test */ + public function job_can_be_when_not_initialized_inside_queues() + { + $tenant = Tenant::create([ + 'id' => 'acme', + ]); + + tenancy()->initialize($tenant); + + dispatch(new TestJobDeleted($this->valuestore)); + + $this->assertEquals(1, \Illuminate\Support\Facades\Queue::size()); + $this->assertFalse($this->valuestore->has('tenant_id')); + + tenancy()->end(); + $tenant->delete(); + + $this->artisan('queue:work --once'); + + $this->assertFalse($this->valuestore->has('tenant_id')); + $this->assertEquals(0, \Illuminate\Support\Facades\Queue::size()); + } + } class TestJob implements ShouldQueue @@ -281,3 +305,25 @@ class TestJob implements ShouldQueue } } } + + +class TestJobDeleted implements ShouldQueue +{ + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + + /** @var Valuestore */ + protected $valuestore; + + public $deleteWhenCannotIdentify = true; + + public function __construct(Valuestore $valuestore) + { + $this->valuestore = $valuestore; + } + + public function handle() + { + $this->valuestore->put('tenant_id', tenant('id')); + } +} +