From b152fcdf2888c53830723e8e5a3b0810ae630cc8 Mon Sep 17 00:00:00 2001 From: Andriy Karpishyn Date: Sun, 31 May 2026 13:10:48 +0300 Subject: [PATCH 1/2] Add configurable storage connection for workflow models and migrations --- README.md | 28 +++++++++ src/Models/StoredWorkflow.php | 3 + src/Models/StoredWorkflowException.php | 3 + src/Models/StoredWorkflowLog.php | 3 + src/Models/StoredWorkflowSignal.php | 3 + src/Models/StoredWorkflowTimer.php | 3 + src/Support/WorkflowMigration.php | 15 +++++ src/Traits/ResolvesStorageConnection.php | 13 +++++ src/V2/Models/ActivityAttempt.php | 3 + src/V2/Models/ActivityExecution.php | 3 + .../Models/WorkerCompatibilityHeartbeat.php | 3 + src/V2/Models/WorkflowChildCall.php | 3 + src/V2/Models/WorkflowCommand.php | 3 + src/V2/Models/WorkflowFailure.php | 3 + src/V2/Models/WorkflowHistoryEvent.php | 3 + src/V2/Models/WorkflowInstance.php | 3 + src/V2/Models/WorkflowLink.php | 3 + src/V2/Models/WorkflowMemo.php | 3 + src/V2/Models/WorkflowMessage.php | 3 + src/V2/Models/WorkflowRun.php | 3 + src/V2/Models/WorkflowRunLineageEntry.php | 3 + src/V2/Models/WorkflowRunSummary.php | 3 + src/V2/Models/WorkflowRunTimerEntry.php | 3 + src/V2/Models/WorkflowRunWait.php | 3 + src/V2/Models/WorkflowSchedule.php | 3 + .../Models/WorkflowScheduleHistoryEvent.php | 3 + src/V2/Models/WorkflowSearchAttribute.php | 3 + src/V2/Models/WorkflowService.php | 3 + src/V2/Models/WorkflowServiceCall.php | 3 + src/V2/Models/WorkflowServiceEndpoint.php | 3 + src/V2/Models/WorkflowServiceOperation.php | 3 + src/V2/Models/WorkflowSignal.php | 3 + src/V2/Models/WorkflowTask.php | 3 + src/V2/Models/WorkflowTimelineEntry.php | 3 + src/V2/Models/WorkflowTimer.php | 3 + src/V2/Models/WorkflowUpdate.php | 3 + src/config/workflows.php | 6 ++ ...22_01_01_000000_create_workflows_table.php | 4 +- ...1_01_000001_create_workflow_logs_table.php | 4 +- ...1_000002_create_workflow_signals_table.php | 4 +- ...01_000003_create_workflow_timers_table.php | 4 +- ...00004_create_workflow_exceptions_table.php | 4 +- ...05_create_workflow_relationships_table.php | 4 +- ...000100_create_workflow_instances_table.php | 4 +- ...4_05_000101_create_workflow_runs_table.php | 4 +- ...2_create_workflow_history_events_table.php | 4 +- ..._05_000103_create_workflow_tasks_table.php | 4 +- ...00104_create_activity_executions_table.php | 4 +- ..._000105_create_workflow_failures_table.php | 4 +- ...06_create_workflow_run_summaries_table.php | 4 +- ...00107_create_workflow_run_timers_table.php | 4 +- ..._000108_create_workflow_commands_table.php | 4 +- ..._05_000112_create_workflow_links_table.php | 4 +- ..._000124_create_activity_attempts_table.php | 4 +- ..._worker_compatibility_heartbeats_table.php | 4 +- ...9_000128_create_workflow_updates_table.php | 4 +- ...0_create_workflow_signal_records_table.php | 4 +- ...000136_create_workflow_run_waits_table.php | 4 +- ...te_workflow_run_timeline_entries_table.php | 4 +- ...ate_workflow_run_lineage_entries_table.php | 4 +- ...reate_workflow_run_timer_entries_table.php | 4 +- ...000157_create_workflow_schedules_table.php | 4 +- ...reate_workflow_search_attributes_table.php | 4 +- ..._16_000151_create_workflow_memos_table.php | 4 +- ..._000160_create_workflow_messages_table.php | 4 +- ...0170_create_workflow_child_calls_table.php | 4 +- ...workflow_schedule_history_events_table.php | 4 +- ...reate_workflow_service_endpoints_table.php | 4 +- ..._000191_create_workflow_services_table.php | 4 +- ...eate_workflow_service_operations_table.php | 4 +- ...93_create_workflow_service_calls_table.php | 4 +- ...bedded_import_markers_to_workflow_runs.php | 4 +- ...05_000590_add_sticky_execution_columns.php | 4 +- ...get_pressure_to_workflow_run_summaries.php | 4 +- ...riority_and_fairness_to_workflow_tasks.php | 4 +- ...ord_list_to_workflow_search_attributes.php | 4 +- tests/Unit/StorageConnectionTest.php | 40 +++++++++++++ tests/Unit/migrations/MigrationsTest.php | 38 +++++++++++++ .../StorageConnectionMigrationTest.php | 57 +++++++++++++++++++ 79 files changed, 374 insertions(+), 78 deletions(-) create mode 100644 src/Support/WorkflowMigration.php create mode 100644 src/Traits/ResolvesStorageConnection.php create mode 100644 tests/Unit/StorageConnectionTest.php create mode 100644 tests/Unit/migrations/StorageConnectionMigrationTest.php diff --git a/README.md b/README.md index b6149ff9..b60f3f4b 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,34 @@ $workflow->output(); => 'Hello, world!' ``` +## Using a dedicated storage connection + +By default all workflow persistence (every Eloquent model and every migration shipped +by this package) lives on your application's **default** database connection. To isolate +workflow state on its own database — for separate backup/retention/scaling, a different +driver, or tenant isolation — point the package at a dedicated connection: + +```php +// config/workflows.php +'storage' => [ + // null => the application's default connection (the default, unchanged behavior). + 'connection' => Env::dw('DW_STORAGE_CONNECTION', 'WORKFLOW_STORAGE_CONNECTION', null), +], +``` + +```dotenv +# .env — must match a key under config('database.connections') +DW_STORAGE_CONNECTION=durable_workflow +``` + +When set, both the models and the migrations are routed to that connection, so +`php artisan migrate` creates the workflow tables there and all reads/writes target it. +Leaving it `null` preserves today's behavior exactly. + +The schema/database is governed by the connection's own configuration — use +`search_path` for PostgreSQL or `database` for MySQL on that connection. There is no +separate schema option. + ## Sponsors The Durable Workflow package is sustained by the community via sponsors and volunteers. diff --git a/src/Models/StoredWorkflow.php b/src/Models/StoredWorkflow.php index a79f24a3..0fd666df 100644 --- a/src/Models/StoredWorkflow.php +++ b/src/Models/StoredWorkflow.php @@ -13,12 +13,15 @@ use Workflow\States\HasStates; use Workflow\States\WorkflowContinuedStatus; use Workflow\States\WorkflowStatus; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\WorkflowMetadata; use Workflow\WorkflowOptions; use Workflow\WorkflowStub; class StoredWorkflow extends Model { + use ResolvesStorageConnection; + use HasStates; use Prunable; diff --git a/src/Models/StoredWorkflowException.php b/src/Models/StoredWorkflowException.php index 097dee7a..f4f62bf4 100644 --- a/src/Models/StoredWorkflowException.php +++ b/src/Models/StoredWorkflowException.php @@ -5,9 +5,12 @@ namespace Workflow\Models; use Illuminate\Database\Eloquent\Model; +use Workflow\Traits\ResolvesStorageConnection; class StoredWorkflowException extends Model { + use ResolvesStorageConnection; + public const UPDATED_AT = null; /** diff --git a/src/Models/StoredWorkflowLog.php b/src/Models/StoredWorkflowLog.php index 2511b862..95fba939 100644 --- a/src/Models/StoredWorkflowLog.php +++ b/src/Models/StoredWorkflowLog.php @@ -5,9 +5,12 @@ namespace Workflow\Models; use Illuminate\Database\Eloquent\Model; +use Workflow\Traits\ResolvesStorageConnection; class StoredWorkflowLog extends Model { + use ResolvesStorageConnection; + public const UPDATED_AT = null; /** diff --git a/src/Models/StoredWorkflowSignal.php b/src/Models/StoredWorkflowSignal.php index e0255898..09e9a562 100644 --- a/src/Models/StoredWorkflowSignal.php +++ b/src/Models/StoredWorkflowSignal.php @@ -5,9 +5,12 @@ namespace Workflow\Models; use Illuminate\Database\Eloquent\Model; +use Workflow\Traits\ResolvesStorageConnection; class StoredWorkflowSignal extends Model { + use ResolvesStorageConnection; + public const UPDATED_AT = null; /** diff --git a/src/Models/StoredWorkflowTimer.php b/src/Models/StoredWorkflowTimer.php index ed7c2020..a070ecef 100644 --- a/src/Models/StoredWorkflowTimer.php +++ b/src/Models/StoredWorkflowTimer.php @@ -5,9 +5,12 @@ namespace Workflow\Models; use Illuminate\Database\Eloquent\Model; +use Workflow\Traits\ResolvesStorageConnection; class StoredWorkflowTimer extends Model { + use ResolvesStorageConnection; + public const UPDATED_AT = null; /** diff --git a/src/Support/WorkflowMigration.php b/src/Support/WorkflowMigration.php new file mode 100644 index 00000000..058210c4 --- /dev/null +++ b/src/Support/WorkflowMigration.php @@ -0,0 +1,15 @@ +connection; + } +} diff --git a/src/Traits/ResolvesStorageConnection.php b/src/Traits/ResolvesStorageConnection.php new file mode 100644 index 00000000..3de5ded5 --- /dev/null +++ b/src/Traits/ResolvesStorageConnection.php @@ -0,0 +1,13 @@ +connection; + } +} diff --git a/src/V2/Models/ActivityAttempt.php b/src/V2/Models/ActivityAttempt.php index 8edbe59f..a66f8dea 100644 --- a/src/V2/Models/ActivityAttempt.php +++ b/src/V2/Models/ActivityAttempt.php @@ -7,11 +7,14 @@ use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\ActivityAttemptStatus; use Workflow\V2\Support\ConfiguredV2Models; class ActivityAttempt extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/ActivityExecution.php b/src/V2/Models/ActivityExecution.php index cc92e464..6452ee56 100644 --- a/src/V2/Models/ActivityExecution.php +++ b/src/V2/Models/ActivityExecution.php @@ -9,12 +9,15 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Workflow\Serializers\Serializer; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\ActivityStatus; use Workflow\V2\Support\ConfiguredV2Models; use Workflow\V2\Support\ExternalPayloads; class ActivityExecution extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkerCompatibilityHeartbeat.php b/src/V2/Models/WorkerCompatibilityHeartbeat.php index 8076dc71..9be851e0 100644 --- a/src/V2/Models/WorkerCompatibilityHeartbeat.php +++ b/src/V2/Models/WorkerCompatibilityHeartbeat.php @@ -5,9 +5,12 @@ namespace Workflow\V2\Models; use Illuminate\Database\Eloquent\Model; +use Workflow\Traits\ResolvesStorageConnection; class WorkerCompatibilityHeartbeat extends Model { + use ResolvesStorageConnection; + protected $table = 'workflow_worker_compatibility_heartbeats'; protected $guarded = []; diff --git a/src/V2/Models/WorkflowChildCall.php b/src/V2/Models/WorkflowChildCall.php index f3a1ecd1..4c632c9d 100644 --- a/src/V2/Models/WorkflowChildCall.php +++ b/src/V2/Models/WorkflowChildCall.php @@ -6,12 +6,15 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\ChildCallStatus; use Workflow\V2\Enums\ParentClosePolicy; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowChildCall extends Model { + use ResolvesStorageConnection; + public $incrementing = true; protected $table = 'workflow_child_calls'; diff --git a/src/V2/Models/WorkflowCommand.php b/src/V2/Models/WorkflowCommand.php index 94b41bab..e6446e28 100644 --- a/src/V2/Models/WorkflowCommand.php +++ b/src/V2/Models/WorkflowCommand.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; use Workflow\Serializers\Serializer; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\CommandOutcome; use Workflow\V2\Enums\CommandStatus; use Workflow\V2\Enums\CommandType; @@ -20,6 +21,8 @@ class WorkflowCommand extends Model { + use ResolvesStorageConnection; + use HasUlids; private const MESSAGE_COMMAND_TYPES = ['signal', 'update']; diff --git a/src/V2/Models/WorkflowFailure.php b/src/V2/Models/WorkflowFailure.php index b275ffc1..4dce9874 100644 --- a/src/V2/Models/WorkflowFailure.php +++ b/src/V2/Models/WorkflowFailure.php @@ -7,11 +7,14 @@ use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\FailureCategory; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowFailure extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowHistoryEvent.php b/src/V2/Models/WorkflowHistoryEvent.php index 6d3afbe3..327f9351 100644 --- a/src/V2/Models/WorkflowHistoryEvent.php +++ b/src/V2/Models/WorkflowHistoryEvent.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\HistoryEventType; use Workflow\V2\Support\ConfiguredV2Models; use Workflow\V2\Support\ExternalPayloads; @@ -15,6 +16,8 @@ class WorkflowHistoryEvent extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowInstance.php b/src/V2/Models/WorkflowInstance.php index 05e31ab1..b3d412bb 100644 --- a/src/V2/Models/WorkflowInstance.php +++ b/src/V2/Models/WorkflowInstance.php @@ -8,10 +8,13 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowInstance extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowLink.php b/src/V2/Models/WorkflowLink.php index 862c3e48..6be91a06 100644 --- a/src/V2/Models/WorkflowLink.php +++ b/src/V2/Models/WorkflowLink.php @@ -7,10 +7,13 @@ use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowLink extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowMemo.php b/src/V2/Models/WorkflowMemo.php index b8c93036..58cc92d5 100644 --- a/src/V2/Models/WorkflowMemo.php +++ b/src/V2/Models/WorkflowMemo.php @@ -7,10 +7,13 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use InvalidArgumentException; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowMemo extends Model { + use ResolvesStorageConnection; + // Size and count limits (Phase 1 structural limits) public const MAX_MEMOS_PER_RUN = 100; diff --git a/src/V2/Models/WorkflowMessage.php b/src/V2/Models/WorkflowMessage.php index 30ad46ea..006f5853 100644 --- a/src/V2/Models/WorkflowMessage.php +++ b/src/V2/Models/WorkflowMessage.php @@ -6,12 +6,15 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\MessageConsumeState; use Workflow\V2\Enums\MessageDirection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowMessage extends Model { + use ResolvesStorageConnection; + // Structural limits public const MAX_MESSAGES_PER_STREAM = 10000; diff --git a/src/V2/Models/WorkflowRun.php b/src/V2/Models/WorkflowRun.php index 5334c03d..dde9fa6d 100644 --- a/src/V2/Models/WorkflowRun.php +++ b/src/V2/Models/WorkflowRun.php @@ -11,12 +11,15 @@ use Illuminate\Database\Eloquent\Relations\HasOne; use Workflow\Serializers\CodecRegistry; use Workflow\Serializers\Serializer; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\RunStatus; use Workflow\V2\Support\ConfiguredV2Models; use Workflow\V2\Support\ExternalPayloads; class WorkflowRun extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowRunLineageEntry.php b/src/V2/Models/WorkflowRunLineageEntry.php index b10ed8e2..c6689be2 100644 --- a/src/V2/Models/WorkflowRunLineageEntry.php +++ b/src/V2/Models/WorkflowRunLineageEntry.php @@ -6,10 +6,13 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowRunLineageEntry extends Model { + use ResolvesStorageConnection; + public $incrementing = false; protected $table = 'workflow_run_lineage_entries'; diff --git a/src/V2/Models/WorkflowRunSummary.php b/src/V2/Models/WorkflowRunSummary.php index f7050bb7..1b62be7b 100644 --- a/src/V2/Models/WorkflowRunSummary.php +++ b/src/V2/Models/WorkflowRunSummary.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\RunStatus; use Workflow\V2\Support\ConfiguredV2Models; use Workflow\V2\Support\RepairBlockedReason; @@ -14,6 +15,8 @@ class WorkflowRunSummary extends Model { + use ResolvesStorageConnection; + public $incrementing = false; protected $table = 'workflow_run_summaries'; diff --git a/src/V2/Models/WorkflowRunTimerEntry.php b/src/V2/Models/WorkflowRunTimerEntry.php index 2b807db6..230ee7f8 100644 --- a/src/V2/Models/WorkflowRunTimerEntry.php +++ b/src/V2/Models/WorkflowRunTimerEntry.php @@ -8,10 +8,13 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Carbon; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowRunTimerEntry extends Model { + use ResolvesStorageConnection; + public const CURRENT_SCHEMA_VERSION = 1; public $incrementing = false; diff --git a/src/V2/Models/WorkflowRunWait.php b/src/V2/Models/WorkflowRunWait.php index 68d42384..68d8d034 100644 --- a/src/V2/Models/WorkflowRunWait.php +++ b/src/V2/Models/WorkflowRunWait.php @@ -8,10 +8,13 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Carbon; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowRunWait extends Model { + use ResolvesStorageConnection; + public $incrementing = false; protected $table = 'workflow_run_waits'; diff --git a/src/V2/Models/WorkflowSchedule.php b/src/V2/Models/WorkflowSchedule.php index 7fe8496a..2849110f 100644 --- a/src/V2/Models/WorkflowSchedule.php +++ b/src/V2/Models/WorkflowSchedule.php @@ -11,6 +11,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\ScheduleStatus; use Workflow\V2\Support\ConfiguredV2Models; @@ -27,6 +28,8 @@ */ class WorkflowSchedule extends Model { + use ResolvesStorageConnection; + use HasUlids; public const OVERLAP_POLICIES = [ diff --git a/src/V2/Models/WorkflowScheduleHistoryEvent.php b/src/V2/Models/WorkflowScheduleHistoryEvent.php index 08166088..753e88c0 100644 --- a/src/V2/Models/WorkflowScheduleHistoryEvent.php +++ b/src/V2/Models/WorkflowScheduleHistoryEvent.php @@ -9,12 +9,15 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\UniqueConstraintViolationException; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\HistoryEventType; use Workflow\V2\Support\ConfiguredV2Models; use Workflow\V2\Support\HistoryEventPayloadContract; class WorkflowScheduleHistoryEvent extends Model { + use ResolvesStorageConnection; + use HasUlids; /** diff --git a/src/V2/Models/WorkflowSearchAttribute.php b/src/V2/Models/WorkflowSearchAttribute.php index 2cf20216..ee1ae51a 100644 --- a/src/V2/Models/WorkflowSearchAttribute.php +++ b/src/V2/Models/WorkflowSearchAttribute.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use InvalidArgumentException; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; /** @@ -50,6 +51,8 @@ */ class WorkflowSearchAttribute extends Model { + use ResolvesStorageConnection; + // Size limits from v2 plan public const MAX_ATTRIBUTES_PER_RUN = 100; diff --git a/src/V2/Models/WorkflowService.php b/src/V2/Models/WorkflowService.php index 33f18058..9915cb96 100644 --- a/src/V2/Models/WorkflowService.php +++ b/src/V2/Models/WorkflowService.php @@ -8,10 +8,13 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowService extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowServiceCall.php b/src/V2/Models/WorkflowServiceCall.php index 47053b67..638110ea 100644 --- a/src/V2/Models/WorkflowServiceCall.php +++ b/src/V2/Models/WorkflowServiceCall.php @@ -7,11 +7,14 @@ use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\ServiceCallOutcome; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowServiceCall extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowServiceEndpoint.php b/src/V2/Models/WorkflowServiceEndpoint.php index ae467dc2..1c9db626 100644 --- a/src/V2/Models/WorkflowServiceEndpoint.php +++ b/src/V2/Models/WorkflowServiceEndpoint.php @@ -7,10 +7,13 @@ use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowServiceEndpoint extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowServiceOperation.php b/src/V2/Models/WorkflowServiceOperation.php index 6267d76b..58d30347 100644 --- a/src/V2/Models/WorkflowServiceOperation.php +++ b/src/V2/Models/WorkflowServiceOperation.php @@ -8,10 +8,13 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowServiceOperation extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowSignal.php b/src/V2/Models/WorkflowSignal.php index 5f6fab12..a1da578a 100644 --- a/src/V2/Models/WorkflowSignal.php +++ b/src/V2/Models/WorkflowSignal.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Workflow\Serializers\Serializer; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\CommandOutcome; use Workflow\V2\Enums\SignalStatus; use Workflow\V2\Support\ConfiguredV2Models; @@ -15,6 +16,8 @@ class WorkflowSignal extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowTask.php b/src/V2/Models/WorkflowTask.php index fe9d7b70..a4fca40d 100644 --- a/src/V2/Models/WorkflowTask.php +++ b/src/V2/Models/WorkflowTask.php @@ -7,12 +7,15 @@ use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\TaskStatus; use Workflow\V2\Enums\TaskType; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowTask extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowTimelineEntry.php b/src/V2/Models/WorkflowTimelineEntry.php index f43a9180..9193692b 100644 --- a/src/V2/Models/WorkflowTimelineEntry.php +++ b/src/V2/Models/WorkflowTimelineEntry.php @@ -7,10 +7,13 @@ use Carbon\CarbonInterface; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowTimelineEntry extends Model { + use ResolvesStorageConnection; + public $incrementing = false; protected $table = 'workflow_run_timeline_entries'; diff --git a/src/V2/Models/WorkflowTimer.php b/src/V2/Models/WorkflowTimer.php index eb441f49..fa733af8 100644 --- a/src/V2/Models/WorkflowTimer.php +++ b/src/V2/Models/WorkflowTimer.php @@ -7,11 +7,14 @@ use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\TimerStatus; use Workflow\V2\Support\ConfiguredV2Models; class WorkflowTimer extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/V2/Models/WorkflowUpdate.php b/src/V2/Models/WorkflowUpdate.php index f8a37284..ec578730 100644 --- a/src/V2/Models/WorkflowUpdate.php +++ b/src/V2/Models/WorkflowUpdate.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Workflow\Serializers\CodecRegistry; use Workflow\Serializers\Serializer; +use Workflow\Traits\ResolvesStorageConnection; use Workflow\V2\Enums\CommandOutcome; use Workflow\V2\Enums\UpdateStatus; use Workflow\V2\Support\ConfiguredV2Models; @@ -17,6 +18,8 @@ class WorkflowUpdate extends Model { + use ResolvesStorageConnection; + use HasUlids; public $incrementing = false; diff --git a/src/config/workflows.php b/src/config/workflows.php index ef7369c0..c1d6068a 100644 --- a/src/config/workflows.php +++ b/src/config/workflows.php @@ -406,6 +406,12 @@ // be flagged by `workflow:v2:doctor`; JSON is not a registered v2 codec. 'serializer' => Env::dw('DW_SERIALIZER', 'WORKFLOW_SERIALIZER', 'avro'), + 'storage' => [ + // Database connection used for ALL workflow persistence (Eloquent models + migrations). + // null => the application's default connection (preserves existing behavior). + 'connection' => Env::dw('DW_STORAGE_CONNECTION', 'WORKFLOW_STORAGE_CONNECTION', null), + ], + 'prune_age' => '1 month', 'webhooks_route' => Env::dw('DW_WEBHOOKS_ROUTE', 'WORKFLOW_WEBHOOKS_ROUTE', 'webhooks'), diff --git a/src/migrations/2022_01_01_000000_create_workflows_table.php b/src/migrations/2022_01_01_000000_create_workflows_table.php index 6b5d38c0..f73ee94a 100644 --- a/src/migrations/2022_01_01_000000_create_workflows_table.php +++ b/src/migrations/2022_01_01_000000_create_workflows_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { /** * Run the migrations. */ diff --git a/src/migrations/2022_01_01_000001_create_workflow_logs_table.php b/src/migrations/2022_01_01_000001_create_workflow_logs_table.php index 2a2adf7b..cc7d64a1 100644 --- a/src/migrations/2022_01_01_000001_create_workflow_logs_table.php +++ b/src/migrations/2022_01_01_000001_create_workflow_logs_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { /** * Run the migrations. */ diff --git a/src/migrations/2022_01_01_000002_create_workflow_signals_table.php b/src/migrations/2022_01_01_000002_create_workflow_signals_table.php index 0f9944ec..afe8b9e2 100644 --- a/src/migrations/2022_01_01_000002_create_workflow_signals_table.php +++ b/src/migrations/2022_01_01_000002_create_workflow_signals_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { /** * Run the migrations. */ diff --git a/src/migrations/2022_01_01_000003_create_workflow_timers_table.php b/src/migrations/2022_01_01_000003_create_workflow_timers_table.php index d3ee9e4b..0a5857e3 100644 --- a/src/migrations/2022_01_01_000003_create_workflow_timers_table.php +++ b/src/migrations/2022_01_01_000003_create_workflow_timers_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { /** * Run the migrations. */ diff --git a/src/migrations/2022_01_01_000004_create_workflow_exceptions_table.php b/src/migrations/2022_01_01_000004_create_workflow_exceptions_table.php index 6359b789..0a84724d 100644 --- a/src/migrations/2022_01_01_000004_create_workflow_exceptions_table.php +++ b/src/migrations/2022_01_01_000004_create_workflow_exceptions_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { /** * Run the migrations. */ diff --git a/src/migrations/2022_01_01_000005_create_workflow_relationships_table.php b/src/migrations/2022_01_01_000005_create_workflow_relationships_table.php index f8a4a88b..824a22ff 100644 --- a/src/migrations/2022_01_01_000005_create_workflow_relationships_table.php +++ b/src/migrations/2022_01_01_000005_create_workflow_relationships_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { /** * Run the migrations. */ diff --git a/src/migrations/2026_04_05_000100_create_workflow_instances_table.php b/src/migrations/2026_04_05_000100_create_workflow_instances_table.php index aa0adf61..b60e8bce 100644 --- a/src/migrations/2026_04_05_000100_create_workflow_instances_table.php +++ b/src/migrations/2026_04_05_000100_create_workflow_instances_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_instances', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_05_000101_create_workflow_runs_table.php b/src/migrations/2026_04_05_000101_create_workflow_runs_table.php index 194f81cf..f8f3654b 100644 --- a/src/migrations/2026_04_05_000101_create_workflow_runs_table.php +++ b/src/migrations/2026_04_05_000101_create_workflow_runs_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_runs', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_05_000102_create_workflow_history_events_table.php b/src/migrations/2026_04_05_000102_create_workflow_history_events_table.php index 63587549..86e74d7d 100644 --- a/src/migrations/2026_04_05_000102_create_workflow_history_events_table.php +++ b/src/migrations/2026_04_05_000102_create_workflow_history_events_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_history_events', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_05_000103_create_workflow_tasks_table.php b/src/migrations/2026_04_05_000103_create_workflow_tasks_table.php index 59666814..e9000f74 100644 --- a/src/migrations/2026_04_05_000103_create_workflow_tasks_table.php +++ b/src/migrations/2026_04_05_000103_create_workflow_tasks_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_tasks', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_05_000104_create_activity_executions_table.php b/src/migrations/2026_04_05_000104_create_activity_executions_table.php index 9ed62725..91440ff4 100644 --- a/src/migrations/2026_04_05_000104_create_activity_executions_table.php +++ b/src/migrations/2026_04_05_000104_create_activity_executions_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('activity_executions', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_05_000105_create_workflow_failures_table.php b/src/migrations/2026_04_05_000105_create_workflow_failures_table.php index 44938713..e911fa90 100644 --- a/src/migrations/2026_04_05_000105_create_workflow_failures_table.php +++ b/src/migrations/2026_04_05_000105_create_workflow_failures_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_failures', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_05_000106_create_workflow_run_summaries_table.php b/src/migrations/2026_04_05_000106_create_workflow_run_summaries_table.php index 14212afa..32e6e192 100644 --- a/src/migrations/2026_04_05_000106_create_workflow_run_summaries_table.php +++ b/src/migrations/2026_04_05_000106_create_workflow_run_summaries_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_run_summaries', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_05_000107_create_workflow_run_timers_table.php b/src/migrations/2026_04_05_000107_create_workflow_run_timers_table.php index 599987e0..61411f6d 100644 --- a/src/migrations/2026_04_05_000107_create_workflow_run_timers_table.php +++ b/src/migrations/2026_04_05_000107_create_workflow_run_timers_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_run_timers', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_05_000108_create_workflow_commands_table.php b/src/migrations/2026_04_05_000108_create_workflow_commands_table.php index d9f1ddee..0f88d7eb 100644 --- a/src/migrations/2026_04_05_000108_create_workflow_commands_table.php +++ b/src/migrations/2026_04_05_000108_create_workflow_commands_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_commands', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_05_000112_create_workflow_links_table.php b/src/migrations/2026_04_05_000112_create_workflow_links_table.php index 19224d48..9e44e9ac 100644 --- a/src/migrations/2026_04_05_000112_create_workflow_links_table.php +++ b/src/migrations/2026_04_05_000112_create_workflow_links_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_links', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_08_000124_create_activity_attempts_table.php b/src/migrations/2026_04_08_000124_create_activity_attempts_table.php index 6f35f69a..5a5e045c 100644 --- a/src/migrations/2026_04_08_000124_create_activity_attempts_table.php +++ b/src/migrations/2026_04_08_000124_create_activity_attempts_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('activity_attempts', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_08_000126_create_worker_compatibility_heartbeats_table.php b/src/migrations/2026_04_08_000126_create_worker_compatibility_heartbeats_table.php index 2e50380e..b23bbfa0 100644 --- a/src/migrations/2026_04_08_000126_create_worker_compatibility_heartbeats_table.php +++ b/src/migrations/2026_04_08_000126_create_worker_compatibility_heartbeats_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_worker_compatibility_heartbeats', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_09_000128_create_workflow_updates_table.php b/src/migrations/2026_04_09_000128_create_workflow_updates_table.php index 9f10fec6..a3eefc91 100644 --- a/src/migrations/2026_04_09_000128_create_workflow_updates_table.php +++ b/src/migrations/2026_04_09_000128_create_workflow_updates_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_updates', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_09_000130_create_workflow_signal_records_table.php b/src/migrations/2026_04_09_000130_create_workflow_signal_records_table.php index 278b45f4..22ddd2eb 100644 --- a/src/migrations/2026_04_09_000130_create_workflow_signal_records_table.php +++ b/src/migrations/2026_04_09_000130_create_workflow_signal_records_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_signal_records', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_10_000136_create_workflow_run_waits_table.php b/src/migrations/2026_04_10_000136_create_workflow_run_waits_table.php index 99823eae..8bda751e 100644 --- a/src/migrations/2026_04_10_000136_create_workflow_run_waits_table.php +++ b/src/migrations/2026_04_10_000136_create_workflow_run_waits_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_run_waits', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_10_000137_create_workflow_run_timeline_entries_table.php b/src/migrations/2026_04_10_000137_create_workflow_run_timeline_entries_table.php index 67cbe379..7f4933ab 100644 --- a/src/migrations/2026_04_10_000137_create_workflow_run_timeline_entries_table.php +++ b/src/migrations/2026_04_10_000137_create_workflow_run_timeline_entries_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_run_timeline_entries', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_10_000139_create_workflow_run_lineage_entries_table.php b/src/migrations/2026_04_10_000139_create_workflow_run_lineage_entries_table.php index 46ab0932..2b463b6b 100644 --- a/src/migrations/2026_04_10_000139_create_workflow_run_lineage_entries_table.php +++ b/src/migrations/2026_04_10_000139_create_workflow_run_lineage_entries_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_run_lineage_entries', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_11_000140_create_workflow_run_timer_entries_table.php b/src/migrations/2026_04_11_000140_create_workflow_run_timer_entries_table.php index afb5e6f7..ab567c5c 100644 --- a/src/migrations/2026_04_11_000140_create_workflow_run_timer_entries_table.php +++ b/src/migrations/2026_04_11_000140_create_workflow_run_timer_entries_table.php @@ -2,12 +2,12 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; use Workflow\V2\Models\WorkflowRunTimerEntry; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_run_timer_entries', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_14_000157_create_workflow_schedules_table.php b/src/migrations/2026_04_14_000157_create_workflow_schedules_table.php index 286da3a4..80ff55fb 100644 --- a/src/migrations/2026_04_14_000157_create_workflow_schedules_table.php +++ b/src/migrations/2026_04_14_000157_create_workflow_schedules_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_schedules', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_15_000150_create_workflow_search_attributes_table.php b/src/migrations/2026_04_15_000150_create_workflow_search_attributes_table.php index ec3547b6..1e582445 100644 --- a/src/migrations/2026_04_15_000150_create_workflow_search_attributes_table.php +++ b/src/migrations/2026_04_15_000150_create_workflow_search_attributes_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { /** * Create workflow_search_attributes table for typed indexed metadata. * diff --git a/src/migrations/2026_04_16_000151_create_workflow_memos_table.php b/src/migrations/2026_04_16_000151_create_workflow_memos_table.php index 0e85db93..240f0475 100644 --- a/src/migrations/2026_04_16_000151_create_workflow_memos_table.php +++ b/src/migrations/2026_04_16_000151_create_workflow_memos_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_memos', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_16_000160_create_workflow_messages_table.php b/src/migrations/2026_04_16_000160_create_workflow_messages_table.php index 86ede514..ab36e87e 100644 --- a/src/migrations/2026_04_16_000160_create_workflow_messages_table.php +++ b/src/migrations/2026_04_16_000160_create_workflow_messages_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_messages', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_16_000170_create_workflow_child_calls_table.php b/src/migrations/2026_04_16_000170_create_workflow_child_calls_table.php index d914d541..d3976d3c 100644 --- a/src/migrations/2026_04_16_000170_create_workflow_child_calls_table.php +++ b/src/migrations/2026_04_16_000170_create_workflow_child_calls_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::create('workflow_child_calls', static function (Blueprint $table): void { diff --git a/src/migrations/2026_04_16_000180_create_workflow_schedule_history_events_table.php b/src/migrations/2026_04_16_000180_create_workflow_schedule_history_events_table.php index 8836613a..a9485d41 100644 --- a/src/migrations/2026_04_16_000180_create_workflow_schedule_history_events_table.php +++ b/src/migrations/2026_04_16_000180_create_workflow_schedule_history_events_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { private const TABLE = 'workflow_schedule_history_events'; private const WORKFLOW_SCHEDULE_INDEX = 'wf_schedule_history_workflow_schedule_idx'; diff --git a/src/migrations/2026_04_24_000190_create_workflow_service_endpoints_table.php b/src/migrations/2026_04_24_000190_create_workflow_service_endpoints_table.php index 5b9f3d86..543f21f7 100644 --- a/src/migrations/2026_04_24_000190_create_workflow_service_endpoints_table.php +++ b/src/migrations/2026_04_24_000190_create_workflow_service_endpoints_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { private const TABLE = 'workflow_service_endpoints'; private const NAMESPACE_INDEX = 'wf_service_endpoints_namespace_idx'; diff --git a/src/migrations/2026_04_24_000191_create_workflow_services_table.php b/src/migrations/2026_04_24_000191_create_workflow_services_table.php index 44b76e89..b109f7ed 100644 --- a/src/migrations/2026_04_24_000191_create_workflow_services_table.php +++ b/src/migrations/2026_04_24_000191_create_workflow_services_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { private const TABLE = 'workflow_services'; private const ENDPOINT_INDEX = 'wf_services_endpoint_idx'; diff --git a/src/migrations/2026_04_24_000192_create_workflow_service_operations_table.php b/src/migrations/2026_04_24_000192_create_workflow_service_operations_table.php index 7ead471e..56a4404b 100644 --- a/src/migrations/2026_04_24_000192_create_workflow_service_operations_table.php +++ b/src/migrations/2026_04_24_000192_create_workflow_service_operations_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { private const TABLE = 'workflow_service_operations'; private const ENDPOINT_INDEX = 'wf_service_ops_endpoint_idx'; diff --git a/src/migrations/2026_04_24_000193_create_workflow_service_calls_table.php b/src/migrations/2026_04_24_000193_create_workflow_service_calls_table.php index 40345746..8b380f91 100644 --- a/src/migrations/2026_04_24_000193_create_workflow_service_calls_table.php +++ b/src/migrations/2026_04_24_000193_create_workflow_service_calls_table.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { private const TABLE = 'workflow_service_calls'; private const ENDPOINT_INDEX = 'wf_service_calls_endpoint_idx'; diff --git a/src/migrations/2026_05_05_000200_add_embedded_import_markers_to_workflow_runs.php b/src/migrations/2026_05_05_000200_add_embedded_import_markers_to_workflow_runs.php index 0474beae..fada91a4 100644 --- a/src/migrations/2026_05_05_000200_add_embedded_import_markers_to_workflow_runs.php +++ b/src/migrations/2026_05_05_000200_add_embedded_import_markers_to_workflow_runs.php @@ -2,11 +2,11 @@ declare(strict_types=1); -use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Workflow\Support\WorkflowMigration; -return new class() extends Migration { +return new class() extends WorkflowMigration { public function up(): void { Schema::table('workflow_runs', static function (Blueprint $table): void { diff --git a/src/migrations/2026_05_05_000590_add_sticky_execution_columns.php b/src/migrations/2026_05_05_000590_add_sticky_execution_columns.php index 7e3db9a1..3f386abf 100644 --- a/src/migrations/2026_05_05_000590_add_sticky_execution_columns.php +++ b/src/migrations/2026_05_05_000590_add_sticky_execution_columns.php @@ -1,10 +1,10 @@ 'secondary', + ]); + + // StoredWorkflow (v1), WorkflowRun (v2 resolve-path) and WorkflowMessage + // (v2 hardcoded-usage) all route through the same trait, so the + // hardcoded and ConfiguredV2Models::resolve() call sites agree. + $this->assertSame('secondary', (new StoredWorkflow())->getConnectionName()); + $this->assertSame('secondary', (new WorkflowRun())->getConnectionName()); + $this->assertSame('secondary', (new WorkflowMessage())->getConnectionName()); + } + + public function testModelsFallBackToDefaultConnectionWhenUnset(): void + { + config([ + 'workflows.storage.connection' => null, + ]); + + // null config preserves the historical behavior: the model reports its + // own connection (null => the application's default connection). + $this->assertNull((new StoredWorkflow())->getConnectionName()); + $this->assertNull((new WorkflowRun())->getConnectionName()); + $this->assertNull((new WorkflowMessage())->getConnectionName()); + } +} diff --git a/tests/Unit/migrations/MigrationsTest.php b/tests/Unit/migrations/MigrationsTest.php index ab251c15..0a6ca7b5 100644 --- a/tests/Unit/migrations/MigrationsTest.php +++ b/tests/Unit/migrations/MigrationsTest.php @@ -68,6 +68,44 @@ public function testV2MigrationSlateDoesNotUseSchemaDetectionGuards(): void ); } + /** + * Every package migration must extend Workflow\Support\WorkflowMigration + * so it honors the configurable workflows.storage.connection. The default + * `php artisan make:migration` output extends the framework's bare + * Illuminate\Database\Migrations\Migration, which silently lands the + * workflow tables on the application's default connection. This contract + * fails closed when a newly generated migration forgets the swap. + */ + public function testEveryPackageMigrationExtendsWorkflowMigrationBase(): void + { + $files = glob(dirname(__DIR__, 3) . '/src/migrations/*.php') ?: []; + + $this->assertNotEmpty($files); + + $violations = []; + + foreach ($files as $file) { + $contents = file_get_contents($file); + + $this->assertIsString($contents); + + if (! str_contains($contents, 'extends WorkflowMigration')) { + $violations[] = basename($file) . ' does not extend WorkflowMigration'; + } + + if (preg_match('/extends\s+Migration\b/', $contents) === 1) { + $violations[] = basename($file) . ' still extends the framework Migration base'; + } + } + + $this->assertSame( + [], + $violations, + 'Every package migration must extend Workflow\Support\WorkflowMigration so it ' + . 'honors workflows.storage.connection (regenerate with the package base class).', + ); + } + /** * Mirrors `App\Support\MigrationAdoption::createdTablesIn()` in the * `durableworkflow/server` package. That class drives BLK-S002 recovery diff --git a/tests/Unit/migrations/StorageConnectionMigrationTest.php b/tests/Unit/migrations/StorageConnectionMigrationTest.php new file mode 100644 index 00000000..b1dc6c6a --- /dev/null +++ b/tests/Unit/migrations/StorageConnectionMigrationTest.php @@ -0,0 +1,57 @@ +secondaryDatabase !== '' && is_file($this->secondaryDatabase)) { + @unlink($this->secondaryDatabase); + } + } + + public function testWorkflowMigrationsRunOnConfiguredStorageConnection(): void + { + $default = (string) config('database.default'); + + $this->assertNotSame('secondary', $default); + + foreach (['workflows', 'workflow_runs', 'workflow_messages'] as $table) { + $this->assertTrue( + Schema::connection('secondary')->hasTable($table), + "Expected the {$table} table to be created on the secondary connection.", + ); + + $this->assertFalse( + Schema::connection($default)->hasTable($table), + "Did not expect the {$table} table on the default connection.", + ); + } + } + + protected function defineEnvironment($app): void + { + $this->secondaryDatabase = (string) tempnam(sys_get_temp_dir(), 'wf_storage_'); + + $app['config']->set('database.connections.secondary', [ + 'driver' => 'sqlite', + 'database' => $this->secondaryDatabase, + 'prefix' => '', + 'foreign_key_constraints' => false, + ]); + + // Route every workflow model and migration to the secondary connection + // for the lifetime of this test class. + $app['config']->set('workflows.storage.connection', 'secondary'); + } +} From 2758b9073643fda16c7681c2a1d798f22ccbe66b Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Sun, 31 May 2026 21:26:43 +0000 Subject: [PATCH 2/2] Apply workflow storage connection style fixes --- src/V2/Models/WorkflowSchedule.php | 3 +-- .../2026_05_05_000590_add_sticky_execution_columns.php | 10 ++++++---- ...story_budget_pressure_to_workflow_run_summaries.php | 5 +---- ...300_add_priority_and_fairness_to_workflow_tasks.php | 10 ++-------- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/V2/Models/WorkflowSchedule.php b/src/V2/Models/WorkflowSchedule.php index 2849110f..aff05a70 100644 --- a/src/V2/Models/WorkflowSchedule.php +++ b/src/V2/Models/WorkflowSchedule.php @@ -373,8 +373,7 @@ public function recordFire( ?string $runId, string $outcome, ?DateTimeInterface $occurrenceTime = null, - ): void - { + ): void { $firedAt = now(); $actions = $this->recent_actions ?? []; diff --git a/src/migrations/2026_05_05_000590_add_sticky_execution_columns.php b/src/migrations/2026_05_05_000590_add_sticky_execution_columns.php index 3f386abf..3604a4c5 100644 --- a/src/migrations/2026_05_05_000590_add_sticky_execution_columns.php +++ b/src/migrations/2026_05_05_000590_add_sticky_execution_columns.php @@ -1,5 +1,7 @@ string('sticky_worker_id') ->nullable() @@ -21,7 +23,7 @@ public function up(): void } }); - Schema::table('workflow_tasks', function (Blueprint $table): void { + Schema::table('workflow_tasks', static function (Blueprint $table): void { if (! Schema::hasColumn('workflow_tasks', 'sticky_worker_id')) { $table->string('sticky_worker_id') ->nullable() @@ -50,7 +52,7 @@ public function up(): void public function down(): void { - Schema::table('workflow_tasks', function (Blueprint $table): void { + Schema::table('workflow_tasks', static function (Blueprint $table): void { foreach (['sticky_worker_id', 'sticky_until', 'sticky_replay_mode', 'sticky_claimed_at'] as $column) { if (Schema::hasColumn('workflow_tasks', $column)) { $table->dropColumn($column); @@ -58,7 +60,7 @@ public function down(): void } }); - Schema::table('workflow_runs', function (Blueprint $table): void { + Schema::table('workflow_runs', static function (Blueprint $table): void { foreach (['sticky_worker_id', 'sticky_until'] as $column) { if (Schema::hasColumn('workflow_runs', $column)) { $table->dropColumn($column); diff --git a/src/migrations/2026_05_08_000200_add_history_budget_pressure_to_workflow_run_summaries.php b/src/migrations/2026_05_08_000200_add_history_budget_pressure_to_workflow_run_summaries.php index c3fec73c..1bb0ab1e 100644 --- a/src/migrations/2026_05_08_000200_add_history_budget_pressure_to_workflow_run_summaries.php +++ b/src/migrations/2026_05_08_000200_add_history_budget_pressure_to_workflow_run_summaries.php @@ -24,10 +24,7 @@ public function down(): void { Schema::table('workflow_run_summaries', static function (Blueprint $table): void { $table->dropIndex('workflow_run_summaries_history_budget_pressure_index'); - $table->dropColumn([ - 'history_fan_out', - 'history_budget_pressure', - ]); + $table->dropColumn(['history_fan_out', 'history_budget_pressure']); }); } }; diff --git a/src/migrations/2026_05_09_000300_add_priority_and_fairness_to_workflow_tasks.php b/src/migrations/2026_05_09_000300_add_priority_and_fairness_to_workflow_tasks.php index 14429765..67c07037 100644 --- a/src/migrations/2026_05_09_000300_add_priority_and_fairness_to_workflow_tasks.php +++ b/src/migrations/2026_05_09_000300_add_priority_and_fairness_to_workflow_tasks.php @@ -32,14 +32,8 @@ public function up(): void ->default(1) ->after('fairness_key'); - $table->index( - ['queue', 'status', 'priority', 'available_at'], - 'workflow_tasks_dispatch_order_index', - ); - $table->index( - ['queue', 'status', 'fairness_key'], - 'workflow_tasks_fairness_class_index', - ); + $table->index(['queue', 'status', 'priority', 'available_at'], 'workflow_tasks_dispatch_order_index'); + $table->index(['queue', 'status', 'fairness_key'], 'workflow_tasks_fairness_class_index'); }); }