class JobDispatchedInTransactionUsesAfterCommitRule implements Rule

A queued job dispatched inside a DB::transaction(...) closure must defer its dispatch until the transaction commits, by chaining ->afterCommit() on the dispatch, declaring $afterCommit = true, implementing ShouldQueueAfterCommit, or using a queue connection that does either.

A queued job pushed during an open transaction can be picked up by a worker before the transaction commits (a fast worker racing the still open connection): the job then loads rows that are not visible yet and fails, or silently operates on half written state. Worse, if the transaction rolls back the job still runs against data that never existed. afterCommit holds the dispatch until the outermost transaction commits, and drops it entirely on rollback.

Unlike upstream, which assumes Laravel's queue config, the rule reports only a dispatch whose queue connection is known to push outside the transaction: Hypervel defaults after_commit to true for every driver except sync and database, and a database queue on the transaction's own connection inserts inside it. Anything the analysis cannot establish (an environment-dependent connection, a custom driver, failover, an enclosing transaction or a job constructor that changes its settings) stays silent, as do a deliberate beforeCommit(), the outbox and afterResponse().

Scope and limits:

  • Only the transaction callback's closure or arrow function form is inspected. The manual DB::beginTransaction() ... DB::commit() form has no closure to bound the analysis and is not covered.
  • Job::dispatch(...), Job::dispatchIf(...), Job::dispatchUnless(...), the dispatch() helper and Bus::dispatch() are checked, for a job named in the call. A literal condition that fails dispatches nothing. Synchronous dispatch (dispatchSync, dispatch_sync) runs inline within the transaction by design.
  • A dispatch's own settings only count when they are syntactically chained on it.
  • Unlike upstream, the walk does not enter nested closures, functions or classes: they run later, never or at an unknown time (a DB::afterCommit() callback, for example). A nested transaction is checked from its own call.

Traits

Constants

private CHAIN_SETTINGS

The setting each dispatch chain method changes, by lowercase method name.

private SETTING_PROPERTIES

The job properties holding those settings.

private SETTING_FREE_METHODS

The Queueable methods a job constructor may call without changing those settings.

private ASYNC_DRIVERS

The after_commit default each built-in connector applies, for the drivers that can enqueue outside the transaction.

Properties

protected Container|null $container from  HasContainer

Methods

void
setContainer(Container $container)

Set the container used for resolution.

getContainer()

Return the current container.

mixed
resolve(string $abstract)

Resolve the given type from the container.

__construct(ReflectionProvider $reflectionProvider, ConfigParser $configParser, InitializerExprTypeResolver $initializerExprTypeResolver, ConstructorParser $constructorParser, RuntimeInputs $runtimeInputs)

Create a new rule instance.

string
getNodeType()

Get the node type the rule inspects.

array
processNode(Node $node, Scope $scope)

Report queued jobs dispatched inside a transaction that do not wait for it to commit.

Details

in HasContainer at line 19
void setContainer(Container $container)

Set the container used for resolution.

Parameters

Container $container

Return Value

void

in HasContainer at line 27
Container getContainer()

Return the current container.

Return Value

Container

in HasContainer at line 35
mixed resolve(string $abstract)

Resolve the given type from the container.

Parameters

string $abstract

Return Value

mixed

at line 191
__construct(ReflectionProvider $reflectionProvider, ConfigParser $configParser, InitializerExprTypeResolver $initializerExprTypeResolver, ConstructorParser $constructorParser, RuntimeInputs $runtimeInputs)

Create a new rule instance.

Parameters

ReflectionProvider $reflectionProvider
ConfigParser $configParser
InitializerExprTypeResolver $initializerExprTypeResolver
ConstructorParser $constructorParser
RuntimeInputs $runtimeInputs

at line 203
string getNodeType()

Get the node type the rule inspects.

Return Value

string

at line 215
array processNode(Node $node, Scope $scope)

Report queued jobs dispatched inside a transaction that do not wait for it to commit.

Parameters

Node $node
Scope $scope

Return Value

array