Skip to content

Commit f9e1c4f

Browse files
TD-S052: WORKFLOW_SERIALIZER env override for payload codec
Operators can now select the payload codec at deploy time via the WORKFLOW_SERIALIZER env var (default "avro") without rebuilding the image or mounting a config override file. This unblocks polyglot deployments where the published server image previously had no way to change the codec without a rebuild (#376, #377). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8aabd3e commit f9e1c4f

2 files changed

Lines changed: 72 additions & 24 deletions

File tree

src/config/workflows.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,17 @@
131131
// Payload codec name. v2 defaults to "avro" for typed binary payloads
132132
// with cross-language type fidelity (int stays int, float stays float).
133133
//
134+
// Overridable at deploy time via the WORKFLOW_SERIALIZER env var so
135+
// operators can pin a different codec (e.g. "json" during migration)
136+
// without rebuilding the image or mounting a config override file.
137+
//
134138
// "json" is retained for decoding existing data only. It is not
135139
// recommended for new v2 workflows. Legacy PHP-only codecs
136140
// ("workflow-serializer-y", "workflow-serializer-base64") remain
137141
// supported for reading v1 history but are not recommended for new
138142
// workflows. Setting this to a legacy codec will be flagged by
139143
// `workflow:v2:doctor`.
140-
'serializer' => 'avro',
144+
'serializer' => env('WORKFLOW_SERIALIZER', 'avro'),
141145

142146
'prune_age' => '1 month',
143147

tests/Unit/Config/WorkflowsConfigTest.php

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,75 @@ final class WorkflowsConfigTest extends TestCase
1010
{
1111
public function testConfigIsLoaded(): void
1212
{
13-
$config = require dirname(__DIR__, 3) . '/src/config/workflows.php';
14-
15-
$this->assertNotEmpty($config, 'The workflows config file is not loaded.');
16-
17-
$expectedConfig = [
18-
'workflows_folder' => 'Workflows',
19-
'stored_workflow_model' => \Workflow\Models\StoredWorkflow::class,
20-
'stored_workflow_exception_model' => \Workflow\Models\StoredWorkflowException::class,
21-
'stored_workflow_log_model' => \Workflow\Models\StoredWorkflowLog::class,
22-
'stored_workflow_signal_model' => \Workflow\Models\StoredWorkflowSignal::class,
23-
'stored_workflow_timer_model' => \Workflow\Models\StoredWorkflowTimer::class,
24-
'workflow_relationships_table' => 'workflow_relationships',
25-
'serializer' => 'avro',
26-
'prune_age' => '1 month',
27-
'webhooks_route' => env('WORKFLOW_WEBHOOKS_ROUTE', 'webhooks'),
28-
];
13+
$previousSerializer = getenv('WORKFLOW_SERIALIZER') === false ? null : getenv('WORKFLOW_SERIALIZER');
14+
putenv('WORKFLOW_SERIALIZER');
15+
unset($_ENV['WORKFLOW_SERIALIZER'], $_SERVER['WORKFLOW_SERIALIZER']);
16+
17+
try {
18+
$config = require dirname(__DIR__, 3) . '/src/config/workflows.php';
19+
20+
$this->assertNotEmpty($config, 'The workflows config file is not loaded.');
21+
22+
$expectedConfig = [
23+
'workflows_folder' => 'Workflows',
24+
'stored_workflow_model' => \Workflow\Models\StoredWorkflow::class,
25+
'stored_workflow_exception_model' => \Workflow\Models\StoredWorkflowException::class,
26+
'stored_workflow_log_model' => \Workflow\Models\StoredWorkflowLog::class,
27+
'stored_workflow_signal_model' => \Workflow\Models\StoredWorkflowSignal::class,
28+
'stored_workflow_timer_model' => \Workflow\Models\StoredWorkflowTimer::class,
29+
'workflow_relationships_table' => 'workflow_relationships',
30+
'serializer' => 'avro',
31+
'prune_age' => '1 month',
32+
'webhooks_route' => env('WORKFLOW_WEBHOOKS_ROUTE', 'webhooks'),
33+
];
34+
35+
foreach ($expectedConfig as $key => $expectedValue) {
36+
$this->assertTrue(array_key_exists($key, $config), "The config key [workflows.{$key}] is missing.");
37+
38+
$this->assertEquals(
39+
$expectedValue,
40+
$config[$key],
41+
"The config key [workflows.{$key}] does not match the expected value."
42+
);
43+
}
44+
} finally {
45+
if ($previousSerializer === null) {
46+
putenv('WORKFLOW_SERIALIZER');
47+
unset($_ENV['WORKFLOW_SERIALIZER'], $_SERVER['WORKFLOW_SERIALIZER']);
48+
} else {
49+
putenv(sprintf('WORKFLOW_SERIALIZER=%s', $previousSerializer));
50+
$_ENV['WORKFLOW_SERIALIZER'] = $previousSerializer;
51+
$_SERVER['WORKFLOW_SERIALIZER'] = $previousSerializer;
52+
}
53+
}
54+
}
55+
56+
/**
57+
* Operators must be able to override the payload codec at deploy time
58+
* via the WORKFLOW_SERIALIZER env var without rebuilding the image or
59+
* mounting a config override file.
60+
*/
61+
public function testSerializerHonoursEnvironmentOverride(): void
62+
{
63+
$previous = getenv('WORKFLOW_SERIALIZER') === false ? null : getenv('WORKFLOW_SERIALIZER');
2964

30-
foreach ($expectedConfig as $key => $expectedValue) {
31-
$this->assertTrue(array_key_exists($key, $config), "The config key [workflows.{$key}] is missing.");
65+
putenv('WORKFLOW_SERIALIZER=json');
66+
$_ENV['WORKFLOW_SERIALIZER'] = 'json';
67+
$_SERVER['WORKFLOW_SERIALIZER'] = 'json';
3268

33-
$this->assertEquals(
34-
$expectedValue,
35-
$config[$key],
36-
"The config key [workflows.{$key}] does not match the expected value."
37-
);
69+
try {
70+
$config = require dirname(__DIR__, 3) . '/src/config/workflows.php';
71+
72+
$this->assertSame('json', $config['serializer']);
73+
} finally {
74+
if ($previous === null) {
75+
putenv('WORKFLOW_SERIALIZER');
76+
unset($_ENV['WORKFLOW_SERIALIZER'], $_SERVER['WORKFLOW_SERIALIZER']);
77+
} else {
78+
putenv(sprintf('WORKFLOW_SERIALIZER=%s', $previous));
79+
$_ENV['WORKFLOW_SERIALIZER'] = $previous;
80+
$_SERVER['WORKFLOW_SERIALIZER'] = $previous;
81+
}
3882
}
3983
}
4084

0 commit comments

Comments
 (0)