TaskCompatibility::resolve() loads $task->run even when the caller has already passed that run, provided the run's compatibility is null:
// src/V2/Support/TaskCompatibility.php:15
return self::normalize($task->compatibility)
?? self::normalize($run?->compatibility ?? $task->run?->compatibility);
When $run is given and $run->compatibility is null, the inner ?? falls through to $task->run. Every app that sets no worker-compatibility marker hits this path, because both the task and the run carry null.
Effect
RunSummaryProjector::taskWaitingForCompatibleWorker($task, $run) passes the run explicitly. It runs inside the history projection on every task dispatch, activity outcome, timer and watchdog pass. Each call then costs one extra workflow_runs query per task. In an app with Model::preventLazyLoading() enabled outside production, each call also logs or throws a lazy-loading violation for WorkflowTask::run. One short workflow run produced about 60 of them.
Reproduction
- Leave
workflows.v2.compatibility.current unset (the default).
- Load a
WorkflowTask fresh from the database, so the run relation is not loaded.
- Call
TaskCompatibility::resolve($task, $task->run()->first()).
$task->relationLoaded('run') is now true, and a second workflow_runs query ran.
Present on main (baf795ce) and in 2.4.5.
Suggested fix
Use the passed run when there is one, and fall back to the relation only when no run is passed:
?? self::normalize($run !== null ? $run->compatibility : $task->run?->compatibility);
I'll open a PR with this change and a regression test.
TaskCompatibility::resolve()loads$task->runeven when the caller has already passed that run, provided the run'scompatibilityis null:When
$runis given and$run->compatibilityis null, the inner??falls through to$task->run. Every app that sets no worker-compatibility marker hits this path, because both the task and the run carry null.Effect
RunSummaryProjector::taskWaitingForCompatibleWorker($task, $run)passes the run explicitly. It runs inside the history projection on every task dispatch, activity outcome, timer and watchdog pass. Each call then costs one extraworkflow_runsquery per task. In an app withModel::preventLazyLoading()enabled outside production, each call also logs or throws a lazy-loading violation forWorkflowTask::run. One short workflow run produced about 60 of them.Reproduction
workflows.v2.compatibility.currentunset (the default).WorkflowTaskfresh from the database, so therunrelation is not loaded.TaskCompatibility::resolve($task, $task->run()->first()).$task->relationLoaded('run')is nowtrue, and a secondworkflow_runsquery ran.Present on
main(baf795ce) and in 2.4.5.Suggested fix
Use the passed run when there is one, and fall back to the relation only when no run is passed:
I'll open a PR with this change and a regression test.