dex-python-sdk 1.23.0__tar.gz → 1.26.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/PKG-INFO +27 -32
  2. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/README.md +26 -31
  3. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/__init__.py +1 -2
  4. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_grpc_errors.py +1 -18
  5. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_pull_worker.py +15 -0
  6. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_worker_dispatcher.py +4 -8
  7. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/async_client.py +12 -22
  8. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/async_worker.py +33 -106
  9. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/client.py +10 -23
  10. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/client_options.py +1 -5
  11. dex_python_sdk-1.26.0/dex/dexpb/dex_pb2.py +417 -0
  12. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/dexpb/dex_pb2.pyi +6 -621
  13. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/dexpb/dex_pb2_grpc.py +64 -277
  14. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/flow_config.py +2 -5
  15. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/pull_registration.py +1 -1
  16. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/runtime_errors.py +1 -1
  17. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/worker.py +35 -124
  18. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/worker_options.py +13 -70
  19. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/pyproject.toml +1 -1
  20. dex_python_sdk-1.23.0/dex/_async_worker_service.py +0 -122
  21. dex_python_sdk-1.23.0/dex/_worker_service.py +0 -94
  22. dex_python_sdk-1.23.0/dex/dexpb/dex_pb2.py +0 -551
  23. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/LEGACY_NOTICES.md +0 -0
  24. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/LICENSE +0 -0
  25. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_async_value_hydrator.py +0 -0
  26. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_async_worker_dispatcher.py +0 -0
  27. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_credential_transport.py +0 -0
  28. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_invocation_context.py +0 -0
  29. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_native.pyi +0 -0
  30. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_server_protocol.py +0 -0
  31. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_utils.py +0 -0
  32. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_value_hydrator.py +0 -0
  33. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/_value_mapper.py +0 -0
  34. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/attribute.py +0 -0
  35. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/attribute_match.py +0 -0
  36. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/blob_cache.py +0 -0
  37. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/channel.py +0 -0
  38. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/codec.py +0 -0
  39. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/condition.py +0 -0
  40. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/context.py +0 -0
  41. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/credential.py +0 -0
  42. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/dexpb/__init__.py +0 -0
  43. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/flow.py +0 -0
  44. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/flow_info.py +0 -0
  45. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/flow_options.py +0 -0
  46. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/flow_result.py +0 -0
  47. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/py.typed +0 -0
  48. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/rpc_invoke_options.py +0 -0
  49. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/step.py +0 -0
  50. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/step_execution.py +0 -0
  51. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/stream.py +0 -0
  52. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/subflow.py +0 -0
  53. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/timer.py +0 -0
  54. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/wait.py +0 -0
  55. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/dex/wait_options.py +0 -0
  56. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/Cargo.lock +0 -0
  57. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/Cargo.toml +0 -0
  58. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/Cargo.toml +0 -0
  59. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/LICENSE +0 -0
  60. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/README.md +0 -0
  61. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/src/config.rs +0 -0
  62. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/src/entry.rs +0 -0
  63. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/src/error.rs +0 -0
  64. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/src/format.rs +0 -0
  65. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/src/lib.rs +0 -0
  66. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/src/policy.rs +0 -0
  67. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/src/store.rs +0 -0
  68. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache/tests/blob_cache_integration.rs +0 -0
  69. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache-python/Cargo.toml +0 -0
  70. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache-python/LICENSE +0 -0
  71. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache-python/README.md +0 -0
  72. {dex_python_sdk-1.23.0 → dex_python_sdk-1.26.0}/sdk-rust/crates/dex-blob-cache-python/src/lib.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dex-python-sdk
3
- Version: 1.23.0
3
+ Version: 1.26.0
4
4
  Requires-Dist: grpcio>=1.83.0
5
5
  Requires-Dist: grpcio-status>=1.83.0
6
6
  Requires-Dist: protobuf>=7.35.1
@@ -95,14 +95,17 @@ retain up to four idle credential threads. Sync token lookup must return
95
95
  promptly. By default, no authorization metadata is sent. Dex uses plaintext
96
96
  gRPC, so protect the network path that carries the token.
97
97
 
98
- ## Pull mode
98
+ ## Workers
99
99
 
100
- Set `WorkerOptions.pull` to run a `Worker` or `AsyncWorker` with outbound task
101
- streams. The Worker connects to the Dex server through `server_address` and
102
- does not open a listener. Advertise `worker.worker_target` through
103
- `ClientOptions.worker_target`. A single Flow can override the Client default
104
- with `StartFlowOptions(config_override=FlowConfig(worker_target=...))`; a
105
- SubFlow can use `SubFlowOptions` with the same `FlowConfig` override.
100
+ Workers receive tasks through outbound pull streams. `Worker` and `AsyncWorker`
101
+ need only an outbound connection to the Dex Server at `server_address`. Configure
102
+ capacity and shutdown with `WorkerOptions.pull`; its default is
103
+ `PullWorkerOptions()`. Clients and Flows use pull routing automatically.
104
+
105
+ StartFlow and SubFlow always select pull Workers. Updating Flow configuration
106
+ preserves its existing Worker target; an empty `FlowConfig()` changes nothing.
107
+ Before upgrading an application with active push Flows, use an SDK version that
108
+ supports Worker targets to migrate those Flows to pull routing.
106
109
 
107
110
  ```python
108
111
  import threading
@@ -118,10 +121,11 @@ worker = Worker(
118
121
  )
119
122
  worker_thread = threading.Thread(target=worker.start)
120
123
  worker_thread.start()
124
+ worker.wait_pull_registered(timeout=30)
121
125
  client = Client(
122
126
  registry,
123
127
  cache,
124
- ClientOptions(server_address="dex.example:8801", worker_target=worker.worker_target),
128
+ ClientOptions(server_address="dex.example:8801"),
125
129
  )
126
130
  try:
127
131
  client.start_flow(flow, flow_id, input_value)
@@ -160,10 +164,7 @@ The generated `app_worker_id` uses the first nonempty `DEX_WORKER_INSTANCE`,
160
164
  `POD_NAME`, `HOSTNAME`, or system hostname, plus eight random base32 characters.
161
165
  An override must uniquely identify one Worker process and change after restart.
162
166
  It must contain 1-63 ASCII letters, digits, dots, underscores, or hyphens and
163
- must not equal a registered Flow type. Pull mode cannot configure a bind address
164
- or an advertised address or headless target. Use `WorkerTarget(pull=True)` for
165
- Client defaults or Flow overrides when the Worker target is not directly in
166
- scope.
167
+ must not equal a registered Flow type.
167
168
 
168
169
  Pull streams reconnect after failures. A server-directed reconnect waits for
169
170
  an active task to finish, then waits up to `stop_drain_timeout` for the server
@@ -186,7 +187,7 @@ Worker ID queue to register at least once. Timeout raises `TimeoutError`;
186
187
  async cancellation cancels only that wait. Startup failures reach waiters.
187
188
  A permanent rejection before readiness raises `PullRegistrationError`, whose
188
189
  `queue` and `error` identify the rejected queue and original transport error.
189
- Listening mode and stop before readiness raise `RuntimeError`.
190
+ Stopping before readiness raises `RuntimeError`.
190
191
 
191
192
  Use `worker.pull_registration_state()` for subsequent readiness probes. Its
192
193
  immutable `queues` expose `queue`, `has_registered_stream`, and
@@ -240,7 +241,6 @@ to distinguish reserve pressure from full-capacity rejections. The count exclude
240
241
  full-capacity rejections and unknown names. It counts decline events, including
241
242
  repeated declines of the same Step dispatch while Dex retries it. Read its rate
242
243
  to assess reserve pressure. It never resets and remains available after shutdown.
243
- Listening Workers return zero.
244
244
 
245
245
  ## Flow state I/O
246
246
 
@@ -398,7 +398,7 @@ explicit codec only for a custom encoding or a type Registry cannot derive.
398
398
  partitions them by definition type.
399
399
 
400
400
  `Worker` and `AsyncWorker` synchronize all registered Indexed Attributes with
401
- Dex Server before opening their listener. Existing indexes return immediately;
401
+ Dex Server before opening outbound task streams. Existing indexes return immediately;
402
402
  failure or the default two-minute deadline aborts startup. An indexed
403
403
  `AttributeMap` must provide one fixed `index_key`.
404
404
 
@@ -619,9 +619,9 @@ options = dex.StartFlowOptions(
619
619
  ```
620
620
 
621
621
  Register async hooks with `allow_async_handlers=True` and run them with
622
- `AsyncWorker`. `FAIL` produces `FlowErrorType.FLOW_TIMEOUT` and permits Flow
623
- retry; `CANCEL` cancels without retry. Continue-as-new preserves the deadline,
624
- while retry runs receive a fresh budget. A zero or absent timeout
622
+ `AsyncWorker`. `FAIL` produces `FlowErrorType.FLOW_TIMEOUT` and fails the
623
+ Flow; `CANCEL` cancels it. The deadline is preserved across Flow state
624
+ transfers. A zero or absent timeout
625
625
  disables the feature.
626
626
 
627
627
  `Registry` validates every Flow, Step, RPC signature, durable name, lock, and
@@ -651,12 +651,7 @@ Request IDs are optional for both durable waits. When omitted, the server
651
651
  derives a stable ID from the Step execution or Attribute condition. Reuse an
652
652
  override only for the same wait. `request_timeout` is the total SDK call budget
653
653
  across transparent transport reattachments. Zero waits indefinitely.
654
- Temporal permits 10 in-flight Updates and 2,000 total Updates in History per
655
- Workflow Execution. A caller timeout or cancellation does not finish an
656
- accepted durable wait, so an abandoned handler can retain one in-flight slot.
657
- Set `internal_handler_timeout` only when abandoned waits can approach that
658
- limit. An active call transparently starts another generation, which counts
659
- toward the 2,000-Update history limit. Prefer a value comfortably longer than
654
+ A caller timeout or cancellation does not finish an accepted durable wait. Set `internal_handler_timeout` only when abandoned waits can accumulate. An active call transparently registers its wait again. Prefer a value comfortably longer than
660
655
  normal request timeouts and reconnect gaps. Zero disables timed rollover.
661
656
  Request expiry raises `RequestTimeoutError`.
662
657
 
@@ -701,7 +696,7 @@ SubFlow.
701
696
  Client calls raise concrete `DexServiceError` subclasses. Existing-Flow reads
702
697
  (`describe_flow`, `wait_for_flow`, and `time_travel`) raise
703
698
  `FlowNotFoundError` when the Flow does not exist. Mutations, RPCs, timer/Step
704
- waits, config updates, and continue-as-new triggers raise
699
+ waits, config updates, and state-transfer triggers raise
705
700
  `FlowNotActiveOrNotFoundError` when no running Flow can accept the operation.
706
701
 
707
702
  RPCs also use this error when the target Flow cannot be found, including query-only
@@ -794,8 +789,8 @@ environment:
794
789
  ./run-integration-tests.sh
795
790
  ```
796
791
 
797
- Set `DEX_INTEG_WORKER_MODE=pull` to run the suite with pull Workers instead of
798
- listening Workers. The default is `push`.
792
+ The suite uses server-zd and pull Workers. `DEX_INTEG_ENGINE=zd` remains accepted.
793
+ Set `DEX_SERVER_ZD_BINARY` to reuse a built `dex-server-zd`.
799
794
 
800
795
  ### Measure integration coverage
801
796
 
@@ -868,9 +863,9 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#releases-monorepo-tags) for monorepo ta
868
863
  ## Server protocol compatibility
869
864
 
870
865
  Both `Worker` and `AsyncWorker` call `GetServerInfo`, negotiate the highest
871
- common protocol, synchronize Attribute indexes, and only then bind
872
- WorkerService. The initial Python SDK interval is `[1,1]`. Missing information,
873
- invalid or disjoint intervals, and RPC failures stop startup before binding.
866
+ common protocol, synchronize Attribute indexes, and only then open outbound
867
+ task streams. The initial Python SDK interval is `[1,1]`. Missing information,
868
+ invalid or disjoint intervals, and RPC failures stop startup before polling.
874
869
  The current Python SDK interval is `[1,3]`. Protocol 3 adds hard-delete
875
870
  Attributes. Workers record the negotiated version at startup and reject each
876
871
  handler result that contains a hard-delete Attribute write when it is below 3.
@@ -888,7 +883,7 @@ original terms as described in [LEGACY_NOTICES.md](LEGACY_NOTICES.md).
888
883
 
889
884
  ## Search run inclusion
890
885
 
891
- Dex Server excludes ContinuedAsNew runs by default. Application queries still
886
+ Searches exclude runs with the ContinuedAsNew status by default. server-zd never reports that status. Application queries still
892
887
  need `FlowType` when using shared index slots. An explicit inclusion option
893
888
  removes only the default exclusion; it does not override query filters. Keep
894
889
  the query, inclusion option, and page size consistent across pages.
@@ -79,14 +79,17 @@ retain up to four idle credential threads. Sync token lookup must return
79
79
  promptly. By default, no authorization metadata is sent. Dex uses plaintext
80
80
  gRPC, so protect the network path that carries the token.
81
81
 
82
- ## Pull mode
82
+ ## Workers
83
83
 
84
- Set `WorkerOptions.pull` to run a `Worker` or `AsyncWorker` with outbound task
85
- streams. The Worker connects to the Dex server through `server_address` and
86
- does not open a listener. Advertise `worker.worker_target` through
87
- `ClientOptions.worker_target`. A single Flow can override the Client default
88
- with `StartFlowOptions(config_override=FlowConfig(worker_target=...))`; a
89
- SubFlow can use `SubFlowOptions` with the same `FlowConfig` override.
84
+ Workers receive tasks through outbound pull streams. `Worker` and `AsyncWorker`
85
+ need only an outbound connection to the Dex Server at `server_address`. Configure
86
+ capacity and shutdown with `WorkerOptions.pull`; its default is
87
+ `PullWorkerOptions()`. Clients and Flows use pull routing automatically.
88
+
89
+ StartFlow and SubFlow always select pull Workers. Updating Flow configuration
90
+ preserves its existing Worker target; an empty `FlowConfig()` changes nothing.
91
+ Before upgrading an application with active push Flows, use an SDK version that
92
+ supports Worker targets to migrate those Flows to pull routing.
90
93
 
91
94
  ```python
92
95
  import threading
@@ -102,10 +105,11 @@ worker = Worker(
102
105
  )
103
106
  worker_thread = threading.Thread(target=worker.start)
104
107
  worker_thread.start()
108
+ worker.wait_pull_registered(timeout=30)
105
109
  client = Client(
106
110
  registry,
107
111
  cache,
108
- ClientOptions(server_address="dex.example:8801", worker_target=worker.worker_target),
112
+ ClientOptions(server_address="dex.example:8801"),
109
113
  )
110
114
  try:
111
115
  client.start_flow(flow, flow_id, input_value)
@@ -144,10 +148,7 @@ The generated `app_worker_id` uses the first nonempty `DEX_WORKER_INSTANCE`,
144
148
  `POD_NAME`, `HOSTNAME`, or system hostname, plus eight random base32 characters.
145
149
  An override must uniquely identify one Worker process and change after restart.
146
150
  It must contain 1-63 ASCII letters, digits, dots, underscores, or hyphens and
147
- must not equal a registered Flow type. Pull mode cannot configure a bind address
148
- or an advertised address or headless target. Use `WorkerTarget(pull=True)` for
149
- Client defaults or Flow overrides when the Worker target is not directly in
150
- scope.
151
+ must not equal a registered Flow type.
151
152
 
152
153
  Pull streams reconnect after failures. A server-directed reconnect waits for
153
154
  an active task to finish, then waits up to `stop_drain_timeout` for the server
@@ -170,7 +171,7 @@ Worker ID queue to register at least once. Timeout raises `TimeoutError`;
170
171
  async cancellation cancels only that wait. Startup failures reach waiters.
171
172
  A permanent rejection before readiness raises `PullRegistrationError`, whose
172
173
  `queue` and `error` identify the rejected queue and original transport error.
173
- Listening mode and stop before readiness raise `RuntimeError`.
174
+ Stopping before readiness raises `RuntimeError`.
174
175
 
175
176
  Use `worker.pull_registration_state()` for subsequent readiness probes. Its
176
177
  immutable `queues` expose `queue`, `has_registered_stream`, and
@@ -224,7 +225,6 @@ to distinguish reserve pressure from full-capacity rejections. The count exclude
224
225
  full-capacity rejections and unknown names. It counts decline events, including
225
226
  repeated declines of the same Step dispatch while Dex retries it. Read its rate
226
227
  to assess reserve pressure. It never resets and remains available after shutdown.
227
- Listening Workers return zero.
228
228
 
229
229
  ## Flow state I/O
230
230
 
@@ -382,7 +382,7 @@ explicit codec only for a custom encoding or a type Registry cannot derive.
382
382
  partitions them by definition type.
383
383
 
384
384
  `Worker` and `AsyncWorker` synchronize all registered Indexed Attributes with
385
- Dex Server before opening their listener. Existing indexes return immediately;
385
+ Dex Server before opening outbound task streams. Existing indexes return immediately;
386
386
  failure or the default two-minute deadline aborts startup. An indexed
387
387
  `AttributeMap` must provide one fixed `index_key`.
388
388
 
@@ -603,9 +603,9 @@ options = dex.StartFlowOptions(
603
603
  ```
604
604
 
605
605
  Register async hooks with `allow_async_handlers=True` and run them with
606
- `AsyncWorker`. `FAIL` produces `FlowErrorType.FLOW_TIMEOUT` and permits Flow
607
- retry; `CANCEL` cancels without retry. Continue-as-new preserves the deadline,
608
- while retry runs receive a fresh budget. A zero or absent timeout
606
+ `AsyncWorker`. `FAIL` produces `FlowErrorType.FLOW_TIMEOUT` and fails the
607
+ Flow; `CANCEL` cancels it. The deadline is preserved across Flow state
608
+ transfers. A zero or absent timeout
609
609
  disables the feature.
610
610
 
611
611
  `Registry` validates every Flow, Step, RPC signature, durable name, lock, and
@@ -635,12 +635,7 @@ Request IDs are optional for both durable waits. When omitted, the server
635
635
  derives a stable ID from the Step execution or Attribute condition. Reuse an
636
636
  override only for the same wait. `request_timeout` is the total SDK call budget
637
637
  across transparent transport reattachments. Zero waits indefinitely.
638
- Temporal permits 10 in-flight Updates and 2,000 total Updates in History per
639
- Workflow Execution. A caller timeout or cancellation does not finish an
640
- accepted durable wait, so an abandoned handler can retain one in-flight slot.
641
- Set `internal_handler_timeout` only when abandoned waits can approach that
642
- limit. An active call transparently starts another generation, which counts
643
- toward the 2,000-Update history limit. Prefer a value comfortably longer than
638
+ A caller timeout or cancellation does not finish an accepted durable wait. Set `internal_handler_timeout` only when abandoned waits can accumulate. An active call transparently registers its wait again. Prefer a value comfortably longer than
644
639
  normal request timeouts and reconnect gaps. Zero disables timed rollover.
645
640
  Request expiry raises `RequestTimeoutError`.
646
641
 
@@ -685,7 +680,7 @@ SubFlow.
685
680
  Client calls raise concrete `DexServiceError` subclasses. Existing-Flow reads
686
681
  (`describe_flow`, `wait_for_flow`, and `time_travel`) raise
687
682
  `FlowNotFoundError` when the Flow does not exist. Mutations, RPCs, timer/Step
688
- waits, config updates, and continue-as-new triggers raise
683
+ waits, config updates, and state-transfer triggers raise
689
684
  `FlowNotActiveOrNotFoundError` when no running Flow can accept the operation.
690
685
 
691
686
  RPCs also use this error when the target Flow cannot be found, including query-only
@@ -778,8 +773,8 @@ environment:
778
773
  ./run-integration-tests.sh
779
774
  ```
780
775
 
781
- Set `DEX_INTEG_WORKER_MODE=pull` to run the suite with pull Workers instead of
782
- listening Workers. The default is `push`.
776
+ The suite uses server-zd and pull Workers. `DEX_INTEG_ENGINE=zd` remains accepted.
777
+ Set `DEX_SERVER_ZD_BINARY` to reuse a built `dex-server-zd`.
783
778
 
784
779
  ### Measure integration coverage
785
780
 
@@ -852,9 +847,9 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#releases-monorepo-tags) for monorepo ta
852
847
  ## Server protocol compatibility
853
848
 
854
849
  Both `Worker` and `AsyncWorker` call `GetServerInfo`, negotiate the highest
855
- common protocol, synchronize Attribute indexes, and only then bind
856
- WorkerService. The initial Python SDK interval is `[1,1]`. Missing information,
857
- invalid or disjoint intervals, and RPC failures stop startup before binding.
850
+ common protocol, synchronize Attribute indexes, and only then open outbound
851
+ task streams. The initial Python SDK interval is `[1,1]`. Missing information,
852
+ invalid or disjoint intervals, and RPC failures stop startup before polling.
858
853
  The current Python SDK interval is `[1,3]`. Protocol 3 adds hard-delete
859
854
  Attributes. Workers record the negotiated version at startup and reject each
860
855
  handler result that contains a hard-delete Attribute write when it is below 3.
@@ -872,7 +867,7 @@ original terms as described in [LEGACY_NOTICES.md](LEGACY_NOTICES.md).
872
867
 
873
868
  ## Search run inclusion
874
869
 
875
- Dex Server excludes ContinuedAsNew runs by default. Application queries still
870
+ Searches exclude runs with the ContinuedAsNew status by default. server-zd never reports that status. Application queries still
876
871
  need `FlowType` when using shared index slots. An explicit inclusion option
877
872
  removes only the default exclusion; it does not override query filters. Keep
878
873
  the query, inclusion option, and page size consistent across pages.
@@ -124,7 +124,7 @@ from dex.timer import Timer
124
124
  from dex.wait import Wait
125
125
  from dex.wait_options import WaitForAttributeOptions, WaitForStepCompletionOptions
126
126
  from dex.worker import Worker
127
- from dex.worker_options import PullWorkerOptions, WorkerOptions, WorkerTarget
127
+ from dex.worker_options import PullWorkerOptions, WorkerOptions
128
128
 
129
129
  __all__ = [
130
130
  "BOOL",
@@ -226,7 +226,6 @@ __all__ = [
226
226
  "Worker",
227
227
  "WorkerInvocationError",
228
228
  "WorkerOptions",
229
- "WorkerTarget",
230
229
  "PullWorkerOptions",
231
230
  "PullRegistrationError",
232
231
  "PullRegistrationState",
@@ -10,7 +10,7 @@ from __future__ import annotations
10
10
 
11
11
  import traceback
12
12
  from dataclasses import dataclass
13
- from typing import Any, Literal, cast
13
+ from typing import Literal, cast
14
14
 
15
15
  import grpc
16
16
  from google.protobuf import any_pb2
@@ -165,23 +165,6 @@ def _worker_code(details: pb.ServiceErrorResponse | None) -> grpc.StatusCode | N
165
165
  )
166
166
 
167
167
 
168
- def abort_worker_error(
169
- context: grpc.ServicerContext,
170
- error: BaseException,
171
- ) -> None:
172
- context.abort_with_status(rpc_status.to_status(_worker_error_status(error)))
173
-
174
-
175
- async def async_abort_worker_error(
176
- context: grpc.aio.ServicerContext[Any, Any],
177
- error: BaseException,
178
- ) -> None:
179
- # types-grpcio on 3.11 omits aio abort_with_status; runtime provides it.
180
- await cast(Any, context).abort_with_status(
181
- rpc_status.to_status(_worker_error_status(error))
182
- )
183
-
184
-
185
168
  def _worker_error_status(error: BaseException) -> status_pb2.Status:
186
169
  retry_after_error: RetryAfterError | None = None
187
170
  reported = error
@@ -805,6 +805,21 @@ class PullStream:
805
805
  async with self._send_lock:
806
806
  if request.HasField("task_frame"):
807
807
  frame = request.task_frame
808
+ is_progress_frame = (
809
+ frame.HasField("wait_for")
810
+ and frame.wait_for.WhichOneof("output")
811
+ in ("heartbeat", "stream_write")
812
+ or frame.HasField("execute")
813
+ and frame.execute.WhichOneof("output")
814
+ in ("heartbeat", "stream_write")
815
+ )
816
+ if (
817
+ frame.task_id != self.task_id
818
+ or self._is_final_frame_sent
819
+ or not self._active.is_set()
820
+ and is_progress_frame
821
+ ):
822
+ return
808
823
  if (
809
824
  frame.HasField("rpc")
810
825
  or frame.HasField("worker_error")
@@ -711,6 +711,9 @@ class WorkerDispatcher:
711
711
  mapped.flow_config_override.CopyFrom(
712
712
  self._map_sub_flow_config(options.config_override)
713
713
  )
714
+ mapped.flow_config_override.worker_target.CopyFrom(
715
+ pb.WorkerTarget(is_pull_mode=True)
716
+ )
714
717
  return mapped
715
718
 
716
719
  def _result_attribute_writes(
@@ -761,14 +764,7 @@ class WorkerDispatcher:
761
764
  StepDurability.SYNC: pb.STEP_DURABILITY_SYNC,
762
765
  StepDurability.ASYNC: pb.STEP_DURABILITY_ASYNC,
763
766
  }[config.step_durability]
764
- if config.worker_target is not None:
765
- mapped.worker_target.CopyFrom(
766
- pb.WorkerTarget(
767
- address=config.worker_target.address,
768
- is_headless_address=config.worker_target.headless,
769
- is_pull_mode=config.worker_target.pull,
770
- )
771
- )
767
+ mapped.worker_target.CopyFrom(pb.WorkerTarget(is_pull_mode=True))
772
768
  if config.attribute_store_names is not None:
773
769
  mapped.attribute_store_names.CopyFrom(
774
770
  pb.AttributeStoreNames(names=config.attribute_store_names)
@@ -107,7 +107,7 @@ class AsyncClient:
107
107
  Args:
108
108
  registry: The Flow Registry used for validation and codecs.
109
109
  blob_cache: An open cache used for asynchronous hydration.
110
- options: Service address, default Worker target, and bearer credential;
110
+ options: Service address and bearer credential;
111
111
  ``None`` uses defaults and sends no authorization metadata.
112
112
  """
113
113
  self.registry = registry
@@ -1038,7 +1038,11 @@ class AsyncClient:
1038
1038
  raise
1039
1039
 
1040
1040
  async def update_flow_config(self, flow_id: str, config: FlowConfig) -> None:
1041
- """Replace mutable configuration for an active Flow.
1041
+ """Update specified mutable configuration fields for an active Flow.
1042
+
1043
+ The update affects later decisions and does not recall work already
1044
+ dispatched. Unspecified fields and the existing Worker target remain
1045
+ unchanged. An empty ``FlowConfig()`` leaves all configuration unchanged.
1042
1046
 
1043
1047
  Args:
1044
1048
  flow_id: The non-empty active Flow ID.
@@ -1193,13 +1197,12 @@ class AsyncClient:
1193
1197
  _apply_attribute_store_sync(write, definition)
1194
1198
  _apply_hard_delete_on_null(write, definition)
1195
1199
  mapped.attributes.append(write)
1196
- if (
1197
- options.config_override is not None
1198
- or self.options.worker_target is not None
1199
- ):
1200
- mapped.flow_config_override.CopyFrom(
1201
- self._map_flow_config(options.config_override)
1202
- )
1200
+ mapped.flow_config_override.CopyFrom(
1201
+ self._map_flow_config(options.config_override)
1202
+ )
1203
+ mapped.flow_config_override.worker_target.CopyFrom(
1204
+ pb.WorkerTarget(is_pull_mode=True)
1205
+ )
1203
1206
  return mapped
1204
1207
 
1205
1208
  def _map_flow_config(self, config: FlowConfig | None) -> pb.FlowConfig:
@@ -1236,19 +1239,6 @@ class AsyncClient:
1236
1239
  mapped.attribute_store_names.CopyFrom(
1237
1240
  pb.AttributeStoreNames(names=config.attribute_store_names)
1238
1241
  )
1239
- target = (
1240
- config.worker_target
1241
- if config is not None and config.worker_target is not None
1242
- else self.options.worker_target
1243
- )
1244
- if target is not None:
1245
- mapped.worker_target.CopyFrom(
1246
- pb.WorkerTarget(
1247
- address=target.address,
1248
- is_headless_address=target.headless,
1249
- is_pull_mode=target.pull,
1250
- )
1251
- )
1252
1242
  return mapped
1253
1243
 
1254
1244
  @staticmethod