flo-python 0.1.0__py3-none-any.whl
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.
- flo/__init__.py +214 -0
- flo/actions.py +397 -0
- flo/client.py +284 -0
- flo/exceptions.py +224 -0
- flo/kv.py +257 -0
- flo/queue.py +376 -0
- flo/streams.py +379 -0
- flo/types.py +804 -0
- flo/wire.py +926 -0
- flo/worker.py +421 -0
- flo_python-0.1.0.dist-info/METADATA +561 -0
- flo_python-0.1.0.dist-info/RECORD +13 -0
- flo_python-0.1.0.dist-info/WHEEL +4 -0
flo/__init__.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""Flo Python SDK
|
|
2
|
+
|
|
3
|
+
A Python client for the Flo distributed systems platform.
|
|
4
|
+
|
|
5
|
+
Example:
|
|
6
|
+
import asyncio
|
|
7
|
+
from flo import FloClient
|
|
8
|
+
|
|
9
|
+
async def main():
|
|
10
|
+
async with FloClient("localhost:9000") as client:
|
|
11
|
+
# KV operations
|
|
12
|
+
await client.kv.put("key", b"value")
|
|
13
|
+
value = await client.kv.get("key")
|
|
14
|
+
print(f"Got: {value}")
|
|
15
|
+
|
|
16
|
+
# Queue operations
|
|
17
|
+
seq = await client.queue.enqueue("tasks", b'{"task": "process"}')
|
|
18
|
+
result = await client.queue.dequeue("tasks", 10)
|
|
19
|
+
for msg in result.messages:
|
|
20
|
+
print(f"Message: {msg.payload}")
|
|
21
|
+
await client.queue.ack("tasks", [msg.seq])
|
|
22
|
+
|
|
23
|
+
asyncio.run(main())
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from .client import FloClient
|
|
27
|
+
from .exceptions import (
|
|
28
|
+
BadRequestError,
|
|
29
|
+
ConflictError,
|
|
30
|
+
ConnectionFailedError,
|
|
31
|
+
FloError,
|
|
32
|
+
GenericServerError,
|
|
33
|
+
IncompleteResponseError,
|
|
34
|
+
InternalServerError,
|
|
35
|
+
InvalidChecksumError,
|
|
36
|
+
InvalidEndpointError,
|
|
37
|
+
InvalidMagicError,
|
|
38
|
+
KeyTooLargeError,
|
|
39
|
+
NamespaceTooLargeError,
|
|
40
|
+
NotConnectedError,
|
|
41
|
+
NotFoundError,
|
|
42
|
+
OverloadedError,
|
|
43
|
+
PayloadTooLargeError,
|
|
44
|
+
ProtocolError,
|
|
45
|
+
RateLimitedError,
|
|
46
|
+
ServerError,
|
|
47
|
+
UnauthorizedError,
|
|
48
|
+
UnexpectedEofError,
|
|
49
|
+
UnsupportedVersionError,
|
|
50
|
+
ValidationError,
|
|
51
|
+
ValueTooLargeError,
|
|
52
|
+
)
|
|
53
|
+
from .types import (
|
|
54
|
+
# KV types
|
|
55
|
+
AckOptions,
|
|
56
|
+
# Action types
|
|
57
|
+
ActionDeleteOptions,
|
|
58
|
+
ActionInfo,
|
|
59
|
+
ActionInvokeOptions,
|
|
60
|
+
ActionInvokeResult,
|
|
61
|
+
ActionListOptions,
|
|
62
|
+
ActionListResult,
|
|
63
|
+
ActionRegisterOptions,
|
|
64
|
+
ActionRunStatus,
|
|
65
|
+
ActionStatusOptions,
|
|
66
|
+
ActionType,
|
|
67
|
+
DeleteOptions,
|
|
68
|
+
DequeueOptions,
|
|
69
|
+
DequeueResult,
|
|
70
|
+
DlqListOptions,
|
|
71
|
+
DlqRequeueOptions,
|
|
72
|
+
EnqueueOptions,
|
|
73
|
+
GetOptions,
|
|
74
|
+
HistoryOptions,
|
|
75
|
+
KVEntry,
|
|
76
|
+
Message,
|
|
77
|
+
NackOptions,
|
|
78
|
+
OpCode,
|
|
79
|
+
OptionTag,
|
|
80
|
+
PeekOptions,
|
|
81
|
+
PutOptions,
|
|
82
|
+
ScanOptions,
|
|
83
|
+
ScanResult,
|
|
84
|
+
StatusCode,
|
|
85
|
+
# Stream types
|
|
86
|
+
StorageTier,
|
|
87
|
+
StreamAppendOptions,
|
|
88
|
+
StreamAppendResult,
|
|
89
|
+
StreamGroupAckOptions,
|
|
90
|
+
StreamGroupJoinOptions,
|
|
91
|
+
StreamGroupReadOptions,
|
|
92
|
+
StreamID,
|
|
93
|
+
StreamInfo,
|
|
94
|
+
StreamInfoOptions,
|
|
95
|
+
StreamReadOptions,
|
|
96
|
+
StreamReadResult,
|
|
97
|
+
StreamRecord,
|
|
98
|
+
StreamTrimOptions,
|
|
99
|
+
# Worker types
|
|
100
|
+
TaskAssignment,
|
|
101
|
+
TouchOptions,
|
|
102
|
+
VersionEntry,
|
|
103
|
+
WorkerAwaitOptions,
|
|
104
|
+
WorkerAwaitResult,
|
|
105
|
+
WorkerCompleteOptions,
|
|
106
|
+
WorkerFailOptions,
|
|
107
|
+
WorkerInfo,
|
|
108
|
+
WorkerListOptions,
|
|
109
|
+
WorkerListResult,
|
|
110
|
+
WorkerRegisterOptions,
|
|
111
|
+
WorkerTask,
|
|
112
|
+
WorkerTouchOptions,
|
|
113
|
+
)
|
|
114
|
+
from .worker import ActionContext, Worker, WorkerConfig
|
|
115
|
+
|
|
116
|
+
__version__ = "0.1.0"
|
|
117
|
+
|
|
118
|
+
__all__ = [
|
|
119
|
+
# Client
|
|
120
|
+
"FloClient",
|
|
121
|
+
# High-level Worker API
|
|
122
|
+
"Worker",
|
|
123
|
+
"WorkerConfig",
|
|
124
|
+
"ActionContext",
|
|
125
|
+
# Exceptions
|
|
126
|
+
"FloError",
|
|
127
|
+
"NotConnectedError",
|
|
128
|
+
"ConnectionFailedError",
|
|
129
|
+
"InvalidEndpointError",
|
|
130
|
+
"UnexpectedEofError",
|
|
131
|
+
"ProtocolError",
|
|
132
|
+
"InvalidMagicError",
|
|
133
|
+
"UnsupportedVersionError",
|
|
134
|
+
"InvalidChecksumError",
|
|
135
|
+
"PayloadTooLargeError",
|
|
136
|
+
"IncompleteResponseError",
|
|
137
|
+
"ValidationError",
|
|
138
|
+
"NamespaceTooLargeError",
|
|
139
|
+
"KeyTooLargeError",
|
|
140
|
+
"ValueTooLargeError",
|
|
141
|
+
"ServerError",
|
|
142
|
+
"NotFoundError",
|
|
143
|
+
"BadRequestError",
|
|
144
|
+
"ConflictError",
|
|
145
|
+
"UnauthorizedError",
|
|
146
|
+
"OverloadedError",
|
|
147
|
+
"RateLimitedError",
|
|
148
|
+
"InternalServerError",
|
|
149
|
+
"GenericServerError",
|
|
150
|
+
# Types
|
|
151
|
+
"OpCode",
|
|
152
|
+
"StatusCode",
|
|
153
|
+
"OptionTag",
|
|
154
|
+
# Result types
|
|
155
|
+
"KVEntry",
|
|
156
|
+
"ScanResult",
|
|
157
|
+
"VersionEntry",
|
|
158
|
+
"Message",
|
|
159
|
+
"DequeueResult",
|
|
160
|
+
# Options
|
|
161
|
+
"GetOptions",
|
|
162
|
+
"PutOptions",
|
|
163
|
+
"DeleteOptions",
|
|
164
|
+
"ScanOptions",
|
|
165
|
+
"HistoryOptions",
|
|
166
|
+
"EnqueueOptions",
|
|
167
|
+
"DequeueOptions",
|
|
168
|
+
"AckOptions",
|
|
169
|
+
"NackOptions",
|
|
170
|
+
"DlqListOptions",
|
|
171
|
+
"DlqRequeueOptions",
|
|
172
|
+
"PeekOptions",
|
|
173
|
+
"TouchOptions",
|
|
174
|
+
# Stream types
|
|
175
|
+
"StreamID",
|
|
176
|
+
"StorageTier",
|
|
177
|
+
"StreamRecord",
|
|
178
|
+
"StreamAppendResult",
|
|
179
|
+
"StreamReadResult",
|
|
180
|
+
"StreamInfo",
|
|
181
|
+
# Stream options
|
|
182
|
+
"StreamAppendOptions",
|
|
183
|
+
"StreamReadOptions",
|
|
184
|
+
"StreamTrimOptions",
|
|
185
|
+
"StreamInfoOptions",
|
|
186
|
+
"StreamGroupJoinOptions",
|
|
187
|
+
"StreamGroupReadOptions",
|
|
188
|
+
"StreamGroupAckOptions",
|
|
189
|
+
# Action types
|
|
190
|
+
"ActionType",
|
|
191
|
+
"ActionInfo",
|
|
192
|
+
"ActionRunStatus",
|
|
193
|
+
"ActionInvokeResult",
|
|
194
|
+
"ActionListResult",
|
|
195
|
+
# Action options
|
|
196
|
+
"ActionRegisterOptions",
|
|
197
|
+
"ActionInvokeOptions",
|
|
198
|
+
"ActionStatusOptions",
|
|
199
|
+
"ActionListOptions",
|
|
200
|
+
"ActionDeleteOptions",
|
|
201
|
+
# Worker types
|
|
202
|
+
"TaskAssignment",
|
|
203
|
+
"WorkerTask",
|
|
204
|
+
"WorkerAwaitResult",
|
|
205
|
+
"WorkerInfo",
|
|
206
|
+
"WorkerListResult",
|
|
207
|
+
# Worker options
|
|
208
|
+
"WorkerRegisterOptions",
|
|
209
|
+
"WorkerAwaitOptions",
|
|
210
|
+
"WorkerTouchOptions",
|
|
211
|
+
"WorkerCompleteOptions",
|
|
212
|
+
"WorkerFailOptions",
|
|
213
|
+
"WorkerListOptions",
|
|
214
|
+
]
|
flo/actions.py
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
"""Flo Actions - Low-Level Action/Worker Protocol
|
|
2
|
+
|
|
3
|
+
This module provides low-level operations for actions and workers:
|
|
4
|
+
- Action registration, invocation, and status checking
|
|
5
|
+
- Worker registration, task awaiting, completion, and failure reporting
|
|
6
|
+
|
|
7
|
+
For a higher-level API, see `Worker` in worker.py.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from .types import (
|
|
13
|
+
ActionDeleteOptions,
|
|
14
|
+
ActionInvokeOptions,
|
|
15
|
+
ActionInvokeResult,
|
|
16
|
+
ActionListOptions,
|
|
17
|
+
ActionListResult,
|
|
18
|
+
ActionRegisterOptions,
|
|
19
|
+
ActionRunStatus,
|
|
20
|
+
ActionStatusOptions,
|
|
21
|
+
ActionType,
|
|
22
|
+
OpCode,
|
|
23
|
+
OptionTag,
|
|
24
|
+
WorkerAwaitOptions,
|
|
25
|
+
WorkerAwaitResult,
|
|
26
|
+
WorkerCompleteOptions,
|
|
27
|
+
WorkerFailOptions,
|
|
28
|
+
WorkerListOptions,
|
|
29
|
+
WorkerListResult,
|
|
30
|
+
WorkerRegisterOptions,
|
|
31
|
+
WorkerTouchOptions,
|
|
32
|
+
)
|
|
33
|
+
from .wire import (
|
|
34
|
+
OptionsBuilder,
|
|
35
|
+
parse_task_assignment,
|
|
36
|
+
serialize_action_invoke_value,
|
|
37
|
+
serialize_action_list_value,
|
|
38
|
+
serialize_action_register_value,
|
|
39
|
+
serialize_worker_await_value,
|
|
40
|
+
serialize_worker_complete_value,
|
|
41
|
+
serialize_worker_fail_value,
|
|
42
|
+
serialize_worker_list_value,
|
|
43
|
+
serialize_worker_register_value,
|
|
44
|
+
serialize_worker_touch_value,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if TYPE_CHECKING:
|
|
48
|
+
from .client import FloClient
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ActionOperations:
|
|
52
|
+
"""Action operations for the Flo client.
|
|
53
|
+
|
|
54
|
+
Provides low-level operations for registering and invoking actions.
|
|
55
|
+
For a higher-level API, see `Worker` in worker.py.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def __init__(self, client: "FloClient") -> None:
|
|
59
|
+
self._client = client
|
|
60
|
+
|
|
61
|
+
async def register(
|
|
62
|
+
self,
|
|
63
|
+
name: str,
|
|
64
|
+
action_type: ActionType = ActionType.USER,
|
|
65
|
+
options: ActionRegisterOptions | None = None,
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Register an action.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
name: Action name.
|
|
71
|
+
action_type: Type of action (USER or WASM).
|
|
72
|
+
options: Optional registration options.
|
|
73
|
+
"""
|
|
74
|
+
opts = options or ActionRegisterOptions()
|
|
75
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
76
|
+
|
|
77
|
+
value = serialize_action_register_value(
|
|
78
|
+
action_type=action_type,
|
|
79
|
+
timeout_ms=opts.timeout_ms,
|
|
80
|
+
max_retries=opts.max_retries,
|
|
81
|
+
description=opts.description,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
await self._client._send_and_check(
|
|
85
|
+
OpCode.ACTION_REGISTER,
|
|
86
|
+
namespace,
|
|
87
|
+
name.encode("utf-8"),
|
|
88
|
+
value,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
async def invoke(
|
|
92
|
+
self,
|
|
93
|
+
name: str,
|
|
94
|
+
input_data: bytes,
|
|
95
|
+
options: ActionInvokeOptions | None = None,
|
|
96
|
+
) -> ActionInvokeResult:
|
|
97
|
+
"""Invoke an action.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
name: Action name to invoke.
|
|
101
|
+
input_data: Input data for the action.
|
|
102
|
+
options: Optional invoke options.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
ActionInvokeResult with run_id.
|
|
106
|
+
"""
|
|
107
|
+
opts = options or ActionInvokeOptions()
|
|
108
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
109
|
+
|
|
110
|
+
value = serialize_action_invoke_value(
|
|
111
|
+
input_data=input_data,
|
|
112
|
+
priority=opts.priority,
|
|
113
|
+
idempotency_key=opts.idempotency_key,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
response = await self._client._send_and_check(
|
|
117
|
+
OpCode.ACTION_INVOKE,
|
|
118
|
+
namespace,
|
|
119
|
+
name.encode("utf-8"),
|
|
120
|
+
value,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Response contains run_id as string
|
|
124
|
+
run_id = response.data.decode("utf-8") if response.data else ""
|
|
125
|
+
return ActionInvokeResult(run_id=run_id)
|
|
126
|
+
|
|
127
|
+
async def status(
|
|
128
|
+
self,
|
|
129
|
+
run_id: str,
|
|
130
|
+
options: ActionStatusOptions | None = None,
|
|
131
|
+
) -> ActionRunStatus:
|
|
132
|
+
"""Get action run status.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
run_id: The run ID to check.
|
|
136
|
+
options: Optional status options.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
ActionRunStatus with current status.
|
|
140
|
+
"""
|
|
141
|
+
opts = options or ActionStatusOptions()
|
|
142
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
143
|
+
|
|
144
|
+
response = await self._client._send_and_check(
|
|
145
|
+
OpCode.ACTION_STATUS,
|
|
146
|
+
namespace,
|
|
147
|
+
run_id.encode("utf-8"),
|
|
148
|
+
b"",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Parse status response - format TBD based on server implementation
|
|
152
|
+
# For now return basic status
|
|
153
|
+
return ActionRunStatus(
|
|
154
|
+
run_id=run_id,
|
|
155
|
+
status="unknown",
|
|
156
|
+
result=response.data if response.data else None,
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
async def list(
|
|
160
|
+
self,
|
|
161
|
+
options: ActionListOptions | None = None,
|
|
162
|
+
) -> ActionListResult:
|
|
163
|
+
"""List registered actions.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
options: Optional list options.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
ActionListResult with list of actions.
|
|
170
|
+
"""
|
|
171
|
+
opts = options or ActionListOptions()
|
|
172
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
173
|
+
|
|
174
|
+
value = serialize_action_list_value(limit=opts.limit)
|
|
175
|
+
|
|
176
|
+
await self._client._send_and_check(
|
|
177
|
+
OpCode.ACTION_LIST,
|
|
178
|
+
namespace,
|
|
179
|
+
(opts.prefix or "").encode("utf-8"),
|
|
180
|
+
value,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# Parse list response - format TBD based on server implementation
|
|
184
|
+
return ActionListResult(actions=[])
|
|
185
|
+
|
|
186
|
+
async def delete(
|
|
187
|
+
self,
|
|
188
|
+
name: str,
|
|
189
|
+
options: ActionDeleteOptions | None = None,
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Delete an action.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
name: Action name to delete.
|
|
195
|
+
options: Optional delete options.
|
|
196
|
+
"""
|
|
197
|
+
opts = options or ActionDeleteOptions()
|
|
198
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
199
|
+
|
|
200
|
+
await self._client._send_and_check(
|
|
201
|
+
OpCode.ACTION_DELETE,
|
|
202
|
+
namespace,
|
|
203
|
+
name.encode("utf-8"),
|
|
204
|
+
b"",
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class WorkerOperations:
|
|
209
|
+
"""Worker operations for the Flo client.
|
|
210
|
+
|
|
211
|
+
Provides low-level operations for worker registration and task processing.
|
|
212
|
+
For a higher-level API, see `Worker` in worker.py.
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
def __init__(self, client: "FloClient") -> None:
|
|
216
|
+
self._client = client
|
|
217
|
+
|
|
218
|
+
async def register(
|
|
219
|
+
self,
|
|
220
|
+
worker_id: str,
|
|
221
|
+
task_types: list[str],
|
|
222
|
+
options: WorkerRegisterOptions | None = None,
|
|
223
|
+
) -> None:
|
|
224
|
+
"""Register a worker.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
worker_id: Unique worker identifier.
|
|
228
|
+
task_types: List of task types this worker can handle.
|
|
229
|
+
options: Optional registration options.
|
|
230
|
+
"""
|
|
231
|
+
opts = options or WorkerRegisterOptions()
|
|
232
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
233
|
+
|
|
234
|
+
value = serialize_worker_register_value(task_types)
|
|
235
|
+
|
|
236
|
+
await self._client._send_and_check(
|
|
237
|
+
OpCode.WORKER_REGISTER,
|
|
238
|
+
namespace,
|
|
239
|
+
worker_id.encode("utf-8"),
|
|
240
|
+
value,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
async def await_task(
|
|
244
|
+
self,
|
|
245
|
+
worker_id: str,
|
|
246
|
+
task_types: list[str],
|
|
247
|
+
options: WorkerAwaitOptions | None = None,
|
|
248
|
+
) -> WorkerAwaitResult:
|
|
249
|
+
"""Wait for a task assignment.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
worker_id: Worker identifier.
|
|
253
|
+
task_types: Task types to listen for.
|
|
254
|
+
options: Optional await options (block_ms, timeout_ms).
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
WorkerAwaitResult with task if available.
|
|
258
|
+
"""
|
|
259
|
+
opts = options or WorkerAwaitOptions()
|
|
260
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
261
|
+
|
|
262
|
+
value = serialize_worker_await_value(task_types)
|
|
263
|
+
|
|
264
|
+
# Build options for block_ms and timeout_ms
|
|
265
|
+
options_builder = OptionsBuilder()
|
|
266
|
+
if opts.block_ms is not None:
|
|
267
|
+
options_builder.add_u32(OptionTag.BLOCK_MS, opts.block_ms)
|
|
268
|
+
if opts.timeout_ms is not None:
|
|
269
|
+
options_builder.add_u32(OptionTag.TIMEOUT_MS, opts.timeout_ms)
|
|
270
|
+
|
|
271
|
+
response = await self._client._send_and_check(
|
|
272
|
+
OpCode.WORKER_AWAIT,
|
|
273
|
+
namespace,
|
|
274
|
+
worker_id.encode("utf-8"),
|
|
275
|
+
value,
|
|
276
|
+
options_builder.build(),
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# Parse task assignment response - if empty, no task available
|
|
280
|
+
if not response.data:
|
|
281
|
+
return WorkerAwaitResult(task=None)
|
|
282
|
+
|
|
283
|
+
# Parse task assignment
|
|
284
|
+
task = parse_task_assignment(response.data)
|
|
285
|
+
return WorkerAwaitResult(task=task)
|
|
286
|
+
|
|
287
|
+
async def touch(
|
|
288
|
+
self,
|
|
289
|
+
worker_id: str,
|
|
290
|
+
task_id: str,
|
|
291
|
+
options: WorkerTouchOptions | None = None,
|
|
292
|
+
) -> None:
|
|
293
|
+
"""Extend task lease (heartbeat).
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
worker_id: Worker identifier.
|
|
297
|
+
task_id: Task identifier to extend.
|
|
298
|
+
options: Optional touch options (extend_ms).
|
|
299
|
+
"""
|
|
300
|
+
opts = options or WorkerTouchOptions()
|
|
301
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
302
|
+
|
|
303
|
+
value = serialize_worker_touch_value(task_id, opts.extend_ms)
|
|
304
|
+
|
|
305
|
+
await self._client._send_and_check(
|
|
306
|
+
OpCode.WORKER_TOUCH,
|
|
307
|
+
namespace,
|
|
308
|
+
worker_id.encode("utf-8"),
|
|
309
|
+
value,
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
async def complete(
|
|
313
|
+
self,
|
|
314
|
+
worker_id: str,
|
|
315
|
+
task_id: str,
|
|
316
|
+
result: bytes,
|
|
317
|
+
options: WorkerCompleteOptions | None = None,
|
|
318
|
+
) -> None:
|
|
319
|
+
"""Complete a task successfully.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
worker_id: Worker identifier.
|
|
323
|
+
task_id: Task identifier to complete.
|
|
324
|
+
result: Result data from the task.
|
|
325
|
+
options: Optional complete options.
|
|
326
|
+
"""
|
|
327
|
+
opts = options or WorkerCompleteOptions()
|
|
328
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
329
|
+
|
|
330
|
+
value = serialize_worker_complete_value(task_id, result)
|
|
331
|
+
|
|
332
|
+
await self._client._send_and_check(
|
|
333
|
+
OpCode.WORKER_COMPLETE,
|
|
334
|
+
namespace,
|
|
335
|
+
worker_id.encode("utf-8"),
|
|
336
|
+
value,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
async def fail(
|
|
340
|
+
self,
|
|
341
|
+
worker_id: str,
|
|
342
|
+
task_id: str,
|
|
343
|
+
error_message: str,
|
|
344
|
+
options: WorkerFailOptions | None = None,
|
|
345
|
+
) -> None:
|
|
346
|
+
"""Fail a task.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
worker_id: Worker identifier.
|
|
350
|
+
task_id: Task identifier that failed.
|
|
351
|
+
error_message: Error message describing the failure.
|
|
352
|
+
options: Optional fail options (retry flag).
|
|
353
|
+
"""
|
|
354
|
+
opts = options or WorkerFailOptions()
|
|
355
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
356
|
+
|
|
357
|
+
value = serialize_worker_fail_value(task_id, error_message)
|
|
358
|
+
|
|
359
|
+
# Retry flag goes in TLV options (matches Go SDK)
|
|
360
|
+
options_builder = OptionsBuilder()
|
|
361
|
+
if opts.retry:
|
|
362
|
+
options_builder.add_flag(OptionTag.RETRY)
|
|
363
|
+
|
|
364
|
+
await self._client._send_and_check(
|
|
365
|
+
OpCode.WORKER_FAIL,
|
|
366
|
+
namespace,
|
|
367
|
+
worker_id.encode("utf-8"),
|
|
368
|
+
value,
|
|
369
|
+
options_builder.build(),
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
async def list(
|
|
373
|
+
self,
|
|
374
|
+
options: WorkerListOptions | None = None,
|
|
375
|
+
) -> WorkerListResult:
|
|
376
|
+
"""List registered workers.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
options: Optional list options.
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
WorkerListResult with list of workers.
|
|
383
|
+
"""
|
|
384
|
+
opts = options or WorkerListOptions()
|
|
385
|
+
namespace = self._client.get_namespace(opts.namespace)
|
|
386
|
+
|
|
387
|
+
value = serialize_worker_list_value(opts.limit)
|
|
388
|
+
|
|
389
|
+
await self._client._send_and_check(
|
|
390
|
+
OpCode.WORKER_LIST,
|
|
391
|
+
namespace,
|
|
392
|
+
b"",
|
|
393
|
+
value,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
# Parse list response - format TBD based on server implementation
|
|
397
|
+
return WorkerListResult(workers=[])
|