Skip to content

Commit ddfd2fc

Browse files
Advertise split-role compose nodes with consistent topology identity
Align split-role compose topology identity
1 parent cd14691 commit ddfd2fc

5 files changed

Lines changed: 50 additions & 10 deletions

File tree

README.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -679,10 +679,10 @@ configured process class, and the current execution mode. `execution_mode` is
679679
`local_queue_worker` when `DW_MODE=embedded` routes workflow and activity task
680680
execution through local Laravel queue workers. Set
681681
`DW_SERVER_TOPOLOGY_SHAPE` and `DW_SERVER_PROCESS_CLASS` when a deployment
682-
splits scheduler, matching, or execution work away from the default
683-
`server_http_node` so discovery reports the live node identity instead of a
684-
generic HTTP shape. The published Compose artifacts set these per service for
685-
the supported `server`, `worker`, and `scheduler` nodes, so `GET /api/cluster/info`
682+
splits control-plane, scheduler, matching, or execution work away from the
683+
default `server_http_node` so discovery reports the live node identity instead
684+
of a generic HTTP shape. The published Compose artifacts set these per service
685+
for the supported `server`, `worker`, and `scheduler` nodes, so `GET /api/cluster/info`
686686
and local diagnostics report the same node class the operator actually
687687
deployed. `topology.matching_role` adds the live matching-role
688688
deployment knobs for that node: `queue_wake_enabled`, the matching-role
@@ -1063,11 +1063,12 @@ service and adds a `matching` service running
10631063
`php artisan workflow:v2:repair-pass --loop` so the broad sweep runs in a
10641064
dedicated process operators can scale and supervise independently of API
10651065
ingress and execution workers. It also pins
1066-
`DW_SERVER_TOPOLOGY_SHAPE=split_control_execution` on the `worker`,
1066+
`DW_SERVER_TOPOLOGY_SHAPE=split_control_execution` on the `server`, `worker`,
10671067
`scheduler`, and `matching` services, with `DW_SERVER_PROCESS_CLASS`
1068-
respectively set to `execution_node`, `scheduler_node`, and `matching_node`,
1069-
so migration-shape diagnostics report the live background role instead of the
1070-
standalone defaults while the HTTP server remains the `server_http_node`.
1068+
respectively set to `control_plane_node`, `execution_node`,
1069+
`scheduler_node`, and `matching_node`. That lets the public HTTP service
1070+
advertise the split control-plane shape while execution, scheduler, and
1071+
matching nodes each report their own independent role class.
10711072

10721073
The daemon respects the watchdog loop throttle on every iteration so multiple
10731074
cooperating matching-role processes coexist without duplicating broad-poll

app/Support/ServerTopology.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ private static function shapeAssignments(): array
279279
[
280280
'name' => 'control_plane_node',
281281
'roles' => [
282+
'api_ingress',
282283
'control_plane',
283284
'history_projection',
284285
],
@@ -558,7 +559,7 @@ private static function supportedTopologies(): array
558559
'roles' => ['api_ingress'],
559560
],
560561
'control_plane_node' => [
561-
'roles' => ['control_plane', 'history_projection'],
562+
'roles' => ['api_ingress', 'control_plane', 'history_projection'],
562563
],
563564
'scheduler_node' => [
564565
'roles' => ['scheduler'],

docker-compose.dedicated-matching.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ name: durable-workflow-server
1313
# up
1414
#
1515
# This override:
16+
# - promotes the public HTTP server into the split control-plane class so
17+
# every long-running service in the deployment reports the same
18+
# `split_control_execution` topology family
1619
# - sets DW_V2_MATCHING_ROLE_QUEUE_WAKE=false on the `worker` service so
1720
# execution-only workers no longer broad-poll the durable task table on
1821
# every Looping event
@@ -50,6 +53,11 @@ x-server-environment: &server-environment
5053
DW_AUTH_BACKWARD_COMPATIBLE: ${DW_AUTH_BACKWARD_COMPATIBLE:-true}
5154

5255
services:
56+
server:
57+
environment:
58+
DW_SERVER_TOPOLOGY_SHAPE: split_control_execution
59+
DW_SERVER_PROCESS_CLASS: control_plane_node
60+
5361
worker:
5462
environment:
5563
DW_V2_MATCHING_ROLE_QUEUE_WAKE: "false"

tests/Feature/ClusterInfoTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@ public function test_it_publishes_role_topology_for_the_current_server_node(): v
174174
'topology.shape_assignments.standalone_server.process_classes.0.roles.3',
175175
'history_projection',
176176
)
177+
->assertJsonPath(
178+
'topology.shape_assignments.split_control_execution.process_classes.1.roles.0',
179+
'api_ingress',
180+
)
177181
->assertJsonPath(
178182
'topology.shape_assignments.split_control_execution.process_classes.4.roles.0',
179183
'execution_plane',
@@ -277,6 +281,28 @@ public function test_it_can_publish_a_split_control_execution_process_class(): v
277281
->assertJsonPath('topology.role_catalog.api_ingress.hosted_by_current_node', false);
278282
}
279283

284+
public function test_it_can_publish_a_split_control_execution_control_plane_node(): void
285+
{
286+
config([
287+
'server.topology.shape' => 'split_control_execution',
288+
'server.topology.process_class' => 'control_plane_node',
289+
]);
290+
291+
$response = $this->getJson('/api/cluster/info')->assertOk();
292+
293+
$response
294+
->assertJsonPath('topology.current_shape', 'split_control_execution')
295+
->assertJsonPath('topology.current_process_class', 'control_plane_node')
296+
->assertJsonPath('topology.current_roles.0', 'api_ingress')
297+
->assertJsonPath('topology.current_roles.1', 'control_plane')
298+
->assertJsonPath('topology.current_roles.2', 'history_projection')
299+
->assertJsonCount(3, 'topology.current_roles')
300+
->assertJsonPath('topology.role_catalog.api_ingress.hosted_by_current_node', true)
301+
->assertJsonPath('topology.role_catalog.control_plane.hosted_by_current_node', true)
302+
->assertJsonPath('topology.role_catalog.history_projection.hosted_by_current_node', true)
303+
->assertJsonPath('topology.role_catalog.matching.hosted_by_current_node', false);
304+
}
305+
280306
public function test_it_falls_back_to_the_default_process_class_when_the_configured_class_does_not_match_the_shape(): void
281307
{
282308
config([

tests/Unit/DedicatedMatchingComposeContractTest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public function test_override_swaps_worker_to_execution_only_and_adds_dedicated_
1818
$compose = $this->read('docker-compose.dedicated-matching.yml');
1919

2020
foreach ([
21+
'server:',
22+
'DW_SERVER_PROCESS_CLASS: control_plane_node',
2123
'worker:',
2224
'DW_V2_MATCHING_ROLE_QUEUE_WAKE: "false"',
2325
'DW_SERVER_TOPOLOGY_SHAPE: split_control_execution',
@@ -81,12 +83,13 @@ public function test_published_compose_pins_topology_identity_for_supported_proc
8183
}
8284
}
8385

84-
public function test_override_promotes_background_services_to_split_role_identity(): void
86+
public function test_override_promotes_all_long_running_services_to_split_role_identity(): void
8587
{
8688
$override = $this->read('docker-compose.dedicated-matching.yml');
8789

8890
foreach ([
8991
'DW_SERVER_TOPOLOGY_SHAPE: split_control_execution',
92+
'DW_SERVER_PROCESS_CLASS: control_plane_node',
9093
'DW_SERVER_PROCESS_CLASS: execution_node',
9194
'DW_SERVER_PROCESS_CLASS: scheduler_node',
9295
'DW_SERVER_PROCESS_CLASS: matching_node',
@@ -112,6 +115,7 @@ public function test_readme_documents_the_override_alongside_the_dedicated_daemo
112115
'DW_V2_MATCHING_ROLE_QUEUE_WAKE',
113116
'DW_SERVER_TOPOLOGY_SHAPE',
114117
'DW_SERVER_PROCESS_CLASS',
118+
'control_plane_node',
115119
] as $needle) {
116120
$this->assertStringContainsString(
117121
$needle,

0 commit comments

Comments
 (0)