grctl-sdk-python 0.1.2__py3-none-any.whl → 0.1.3__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.
grctl/client/client.py CHANGED
@@ -11,10 +11,11 @@ from typing import Any
11
11
  import msgspec
12
12
  from ulid import ULID
13
13
 
14
- from grctl.models import DescribeCmd, GrctlAPIResponse, RunInfo
14
+ from grctl.models import DescribeCmd, GrctlAPIResponse, HistoryEvent, RunInfo
15
15
  from grctl.models.command import CmdKind, Command
16
16
  from grctl.models.errors import WorkflowError, WorkflowNotFoundError
17
17
  from grctl.nats.connection import Connection
18
+ from grctl.nats.history_fetch import fetch_run_history
18
19
  from grctl.worker.codec import CodecRegistry
19
20
  from grctl.workflow.handle import WorkflowHandle
20
21
 
@@ -30,36 +31,16 @@ class Client:
30
31
  self._connection = connection
31
32
  self._codec = codec or CodecRegistry()
32
33
 
33
- async def run_workflow(
34
- self,
35
- workflow_type: str,
36
- workflow_id: str,
37
- workflow_input: Any | None = None,
38
- workflow_timeout: timedelta | None = None,
39
- ) -> Any:
40
- """Run a workflow and wait for its result."""
41
- wf_handle = await self.start_workflow(
42
- workflow_type=workflow_type,
43
- workflow_id=workflow_id,
44
- workflow_input=workflow_input,
45
- workflow_timeout=workflow_timeout,
46
- )
47
- timeout = workflow_timeout.total_seconds() if workflow_timeout else None
48
- try:
49
- return await asyncio.wait_for(wf_handle.future, timeout=timeout)
50
- finally:
51
- await wf_handle.future.stop()
52
-
53
- async def get_workflow_handle(self, workflow_id: str) -> WorkflowHandle:
54
- """Get a handle for an already-running workflow."""
34
+ async def describe(self, wf_id: str) -> RunInfo:
35
+ """Describe the latest run for a workflow ID."""
55
36
  cmd = Command(
56
37
  id=str(ULID()),
57
38
  kind=CmdKind.run_describe,
58
39
  timestamp=datetime.now(UTC),
59
- msg=DescribeCmd(wf_id=workflow_id),
40
+ msg=DescribeCmd(wf_id=wf_id),
60
41
  )
61
42
  # Use a routing-only RunInfo — publish_cmd only needs wf_id for subject routing.
62
- routing_info = RunInfo(id="", wf_type="", wf_id=workflow_id)
43
+ routing_info = RunInfo(id="", wf_type="", wf_id=wf_id)
63
44
  response_bytes = await self._connection.publisher.publish_cmd(routing_info, cmd)
64
45
 
65
46
  response = msgspec.msgpack.decode(response_bytes, type=GrctlAPIResponse)
@@ -67,10 +48,34 @@ class Client:
67
48
  error_msg = response.error.message if response.error else "unknown error"
68
49
  error_code = response.error.code if response.error else 0
69
50
  if error_code == ErrWorkflowRunNotFoundCode:
70
- raise WorkflowNotFoundError(f"workflow '{workflow_id}' not found: {error_msg}")
51
+ raise WorkflowNotFoundError(f"workflow '{wf_id}' not found: {error_msg}")
71
52
  raise WorkflowError(f"describe failed (code={error_code}): {error_msg}")
72
53
 
73
- run_info = msgspec.msgpack.decode(response.payload, type=RunInfo)
54
+ return msgspec.msgpack.decode(response.payload, type=RunInfo)
55
+
56
+ async def run_workflow(
57
+ self,
58
+ type: str, # noqa: A002
59
+ id: str, # noqa: A002
60
+ input: Any | None = None, # noqa: A002
61
+ timeout: timedelta | None = None, # noqa: ASYNC109
62
+ ) -> Any:
63
+ """Run a workflow and wait for its result."""
64
+ wf_handle = await self.start_workflow(
65
+ type=type,
66
+ id=id,
67
+ input=input,
68
+ timeout=timeout,
69
+ )
70
+ wait_timeout = timeout.total_seconds() if timeout else None
71
+ try:
72
+ return await asyncio.wait_for(wf_handle.future, timeout=wait_timeout)
73
+ finally:
74
+ await wf_handle.future.stop()
75
+
76
+ async def get_workflow_handle(self, wfid: str) -> WorkflowHandle:
77
+ """Get a handle for an already-running workflow."""
78
+ run_info = await self.describe(wfid)
74
79
 
75
80
  handle = WorkflowHandle(
76
81
  run_info=run_info,
@@ -81,27 +86,40 @@ class Client:
81
86
  await handle.attach()
82
87
  return handle
83
88
 
89
+ async def get_history(self, wf_id: str, run_id: str | None = None) -> list[HistoryEvent]:
90
+ """Return the ordered history events for a workflow run."""
91
+ resolved_run_id = run_id
92
+ if resolved_run_id is None:
93
+ resolved_run_id = (await self.describe(wf_id)).id
94
+
95
+ return await fetch_run_history(
96
+ js=self._connection.js,
97
+ manifest=self._connection.manifest,
98
+ wf_id=wf_id,
99
+ run_id=resolved_run_id,
100
+ )
101
+
84
102
  async def start_workflow(
85
103
  self,
86
- workflow_type: str,
87
- workflow_id: str,
88
- workflow_input: Any | None = None,
89
- workflow_timeout: timedelta | None = None,
104
+ type: str, # noqa: A002
105
+ id: str, # noqa: A002
106
+ input: Any | None = None, # noqa: A002
107
+ timeout: timedelta | None = None, # noqa: ASYNC109
90
108
  ) -> WorkflowHandle:
91
109
  """Start a workflow and return a handle to track and interact with it."""
92
110
  workflow_run_id = str(ULID())
93
111
 
94
112
  run_info = RunInfo(
95
113
  id=workflow_run_id,
96
- wf_type=workflow_type,
97
- wf_id=workflow_id,
98
- timeout=int(workflow_timeout.total_seconds()) if workflow_timeout else None,
114
+ wf_type=type,
115
+ wf_id=id,
116
+ timeout=int(timeout.total_seconds()) if timeout else None,
99
117
  created_at=datetime.now(UTC),
100
118
  )
101
119
 
102
120
  handle = WorkflowHandle(
103
121
  run_info=run_info,
104
- payload=workflow_input,
122
+ payload=input,
105
123
  connection=self._connection,
106
124
  codec=self._codec,
107
125
  )
grctl/models/history.py CHANGED
@@ -202,6 +202,7 @@ class ChildWorkflowStarted(msgspec.Struct):
202
202
  run_id: str
203
203
  wf_type: str
204
204
  wf_id: str
205
+ input: Any | None = None
205
206
 
206
207
 
207
208
  class ParentEventSent(msgspec.Struct):
@@ -209,6 +210,8 @@ class ParentEventSent(msgspec.Struct):
209
210
 
210
211
  event_name: str
211
212
  payload: Any
213
+ parent_wf_type: str
214
+ parent_wf_id: str
212
215
 
213
216
 
214
217
  RunEvents = RunCancelScheduled | RunCancelled | RunCompleted | RunFailed | RunScheduled | RunStarted | RunTimeout
@@ -9,6 +9,36 @@ _FETCH_BATCH_SIZE = 256
9
9
  _FETCH_TIMEOUT_SECONDS = 0.25
10
10
 
11
11
 
12
+ async def fetch_run_history(
13
+ js: JetStreamContext,
14
+ manifest: NatsManifest,
15
+ wf_id: str,
16
+ run_id: str,
17
+ ) -> list[HistoryEvent]:
18
+ history_subject = manifest.history_subject(wf_id=wf_id, run_id=run_id)
19
+ history_stream = manifest.history_stream_name()
20
+ subscription = await js.pull_subscribe(
21
+ subject=history_subject,
22
+ stream=history_stream,
23
+ config=ConsumerConfig(
24
+ deliver_policy=DeliverPolicy.ALL,
25
+ ack_policy=AckPolicy.NONE,
26
+ inactive_threshold=1.0,
27
+ ),
28
+ )
29
+
30
+ events: list[HistoryEvent] = []
31
+ try:
32
+ try:
33
+ while True:
34
+ messages = await subscription.fetch(batch=_FETCH_BATCH_SIZE, timeout=_FETCH_TIMEOUT_SECONDS)
35
+ events.extend(history_decoder(msg.data) for msg in messages if msg.data)
36
+ except (TimeoutError, FetchTimeoutError):
37
+ return events
38
+ finally:
39
+ await subscription.unsubscribe()
40
+
41
+
12
42
  async def fetch_step_history(
13
43
  js: JetStreamContext,
14
44
  manifest: NatsManifest,
grctl/nats/subscriber.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import contextlib
3
3
  import json
4
+ from typing import Any
4
5
 
5
6
  import msgspec
6
7
  from nats.aio.msg import Msg
@@ -11,7 +12,6 @@ from grctl.logging_config import get_logger
11
12
  from grctl.models import directive_decoder
12
13
  from grctl.nats.manifest import NatsManifest
13
14
  from grctl.settings import get_settings
14
- from grctl.worker.run_manager import RunManager
15
15
 
16
16
  logger = get_logger(__name__)
17
17
 
@@ -24,7 +24,7 @@ class Subscriber:
24
24
  js: JetStreamContext,
25
25
  manifest: NatsManifest,
26
26
  wf_types: list[str],
27
- run_manager: RunManager,
27
+ run_manager: Any,
28
28
  ) -> None:
29
29
  self._js = js
30
30
  self._manifest = manifest
grctl/worker/context.py CHANGED
@@ -198,7 +198,12 @@ class Context:
198
198
  )
199
199
  await runtime.record(
200
200
  HistoryKind.parent_event_sent,
201
- ParentEventSent(event_name=event_name, payload=payload),
201
+ ParentEventSent(
202
+ event_name=event_name,
203
+ payload=payload,
204
+ parent_wf_type=self._parent_run.wf_type,
205
+ parent_wf_id=self._parent_run.wf_id,
206
+ ),
202
207
  operation_id,
203
208
  )
204
209
 
@@ -244,7 +249,7 @@ class Context:
244
249
  await handle.start()
245
250
  await runtime.record(
246
251
  HistoryKind.child_started,
247
- ChildWorkflowStarted(run_id=run_id, wf_type=workflow_type, wf_id=workflow_id),
252
+ ChildWorkflowStarted(run_id=run_id, wf_type=workflow_type, wf_id=workflow_id, input=workflow_input),
248
253
  operation_id,
249
254
  )
250
255
  return handle
grctl/worker/worker.py CHANGED
@@ -19,6 +19,7 @@ from grctl.workflow.workflow import Workflow
19
19
 
20
20
  logger = get_logger(__name__)
21
21
 
22
+
22
23
  # Constants
23
24
  DEFAULT_WORKFLOW_TIMEOUT_SECONDS: float = 30.0
24
25
  WORKER_HEARTBEAT_INTERVAL_SECONDS: int = 1
@@ -54,8 +55,10 @@ class Worker:
54
55
  self._connection = connection
55
56
  self._workflow_logger = workflow_logger
56
57
  self._stop_event = asyncio.Event()
58
+ self._startup_event = asyncio.Event()
57
59
  self._subscriber: Subscriber | None = None
58
60
  self._run_manager: RunManager | None = None
61
+ self._startup_error: Exception | None = None
59
62
 
60
63
  @cached_property
61
64
  def worker_name(self) -> str:
@@ -81,31 +84,48 @@ class Worker:
81
84
 
82
85
  Creates RunManager for workflow execution and subscribes to workflow subjects.
83
86
  """
87
+ self._startup_event.clear()
88
+ self._startup_error = None
89
+
84
90
  logger.info(
85
91
  f"Starting worker with {len(self._workflows)} registered workflows",
86
92
  )
87
93
 
88
- self._run_manager = RunManager(
89
- worker_name=self.worker_name,
90
- worker_id=self.worker_id,
91
- workflows=self._workflows,
92
- connection=self._connection,
93
- workflow_logger=self._workflow_logger,
94
- )
95
-
96
- wf_types = [wf.workflow_type for wf in self._workflows]
97
- self._subscriber = Subscriber(
98
- js=self._connection.js,
99
- manifest=self._connection.manifest,
100
- wf_types=wf_types,
101
- run_manager=self._run_manager,
102
- )
103
- await self._subscriber.start()
104
-
105
- logger.info(f"Worker {self.worker_name} ({self.worker_id}) started and ready to process messages")
106
-
107
- # Keep worker alive
108
- await self._process_messages()
94
+ try:
95
+ self._run_manager = RunManager(
96
+ worker_name=self.worker_name,
97
+ worker_id=self.worker_id,
98
+ workflows=self._workflows,
99
+ connection=self._connection,
100
+ workflow_logger=self._workflow_logger,
101
+ )
102
+
103
+ wf_types = [wf.workflow_type for wf in self._workflows]
104
+ self._subscriber = Subscriber(
105
+ js=self._connection.js,
106
+ manifest=self._connection.manifest,
107
+ wf_types=wf_types,
108
+ run_manager=self._run_manager,
109
+ )
110
+ await self._subscriber.start()
111
+ self._startup_event.set()
112
+
113
+ logger.info(f"Worker {self.worker_name} ({self.worker_id}) started and ready to process messages")
114
+
115
+ # Keep worker alive
116
+ await self._process_messages()
117
+ except Exception as exc:
118
+ self._startup_error = exc
119
+ self._startup_event.set()
120
+ raise
121
+
122
+ async def wait_until_ready(self, timeout_ms: float = 5.0) -> None:
123
+ """Wait until worker startup succeeds or fails."""
124
+ await asyncio.wait_for(self._startup_event.wait(), timeout=timeout_ms)
125
+ if self._startup_error is not None:
126
+ raise self._startup_error
127
+ if self._subscriber is None:
128
+ raise RuntimeError("Worker startup completed without creating a subscriber")
109
129
 
110
130
  async def _process_messages(self) -> None:
111
131
  """Keep worker alive to process commands."""
grctl/workflow/future.py CHANGED
@@ -41,6 +41,8 @@ class WorkflowFuture(asyncio.Future[Any]):
41
41
  run_id=run_info.id,
42
42
  handler=self._handle_history_event,
43
43
  )
44
+ self._subscriber_stopped = False
45
+ self.add_done_callback(self._schedule_subscriber_stop)
44
46
  self._history_update_handlers: dict[HistoryKind, Callable[[HistoryEvent], None]] = {
45
47
  HistoryKind.run_scheduled: self._on_non_terminal_event,
46
48
  HistoryKind.run_started: self._on_non_terminal_event,
@@ -54,9 +56,18 @@ class WorkflowFuture(asyncio.Future[Any]):
54
56
  """Start listening for events and publish run command."""
55
57
  await self._subscriber.start()
56
58
 
59
+ def _schedule_subscriber_stop(self, _: asyncio.Future) -> None:
60
+ # done_callback must be sync, so we schedule the async stop as a task.
61
+ if self._subscriber_stopped:
62
+ return
63
+ self._subscriber_stopped = True
64
+ asyncio.ensure_future(self._subscriber.stop()) # noqa: RUF006
65
+
57
66
  async def stop(self) -> None:
58
67
  """Stop listening for events and cleanup."""
59
- await self._subscriber.stop()
68
+ if not self._subscriber_stopped:
69
+ self._subscriber_stopped = True
70
+ await self._subscriber.stop()
60
71
 
61
72
  if not self.done():
62
73
  self.cancel()
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: grctl-sdk-python
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: The Python SDK for the Ground Control
5
- Author: cemevren
6
- Author-email: cemevren <cemevren@gmail.com>
5
+ Author: Cem Evren Ates
6
+ Author-email: Cem Evren Ates <cemevre@gmail.com>
7
7
  License-Expression: Apache-2.0
8
8
  License-File: LICENSE
9
9
  Classifier: Development Status :: 3 - Alpha
@@ -25,18 +25,18 @@ Requires-Dist: pydantic-settings>=2.11.0
25
25
  Requires-Dist: pyyaml>=6.0.3
26
26
  Requires-Dist: pydantic>=2.12.5
27
27
  Requires-Python: >=3.13
28
- Project-URL: Homepage, https://github.com/cemevren/grctl
29
- Project-URL: Documentation, https://cemevren.github.io/grctl/
30
- Project-URL: Repository, https://github.com/cemevren/grctl
31
- Project-URL: Issues, https://github.com/cemevren/grctl/issues
32
- Project-URL: Changelog, https://github.com/cemevren/grctl/blob/main/sdk_python/CHANGELOG.md
28
+ Project-URL: Homepage, https://github.com/grctl/sdk-python
29
+ Project-URL: Documentation, https://grctl.github.io/grctl/
30
+ Project-URL: Repository, https://github.com/grctl/sdk-python
31
+ Project-URL: Issues, https://github.com/grctl/sdk-python/issues
32
+ Project-URL: Changelog, https://github.com/grctl/sdk-python/blob/main/CHANGELOG.md
33
33
  Description-Content-Type: text/markdown
34
34
 
35
35
  # Ground Control Python SDK
36
36
 
37
- The official Python SDK for [Ground Control](https://github.com/cemevren/grctl) — a lightweight workflow orchestration engine built for fail-safe execution.
37
+ The official Python SDK for [Ground Control](https://github.com/grctl/grctl) — a lightweight workflow orchestration engine built for fail-safe execution.
38
38
 
39
- **[Documentation](https://cemevren.github.io/grctl/)**
39
+ **[Documentation](https://grctl.github.io/grctl/)**
40
40
 
41
41
  > [!WARNING]
42
42
  > **Status: Pre-alpha**
@@ -55,12 +55,12 @@ pip install grctl-sdk-python
55
55
 
56
56
  ## Contributing
57
57
 
58
- Contributions are welcome! Please read our [Contributing Guide](https://github.com/cemevren/grctl/blob/main/CONTRIBUTING.md) for more information.
58
+ Contributions are welcome! Please read our [Contributing Guide](https://github.com/grctl/grctl/blob/main/CONTRIBUTING.md) for more information.
59
59
 
60
60
  ## Security
61
61
 
62
- Please see our [Security Policy](https://github.com/cemevren/grctl/blob/main/SECURITY.md) for reporting vulnerabilities.
62
+ Please see our [Security Policy](https://github.com/grctl/grctl/blob/main/SECURITY.md) for reporting vulnerabilities.
63
63
 
64
64
  ## License
65
65
 
66
- This project is licensed under the Apache License 2.0 - see the [LICENSE](https://github.com/cemevren/grctl/blob/main/LICENSE) file for details.
66
+ This project is licensed under the Apache License 2.0 - see the [LICENSE](https://github.com/grctl/grctl/blob/main/LICENSE) file for details.
@@ -1,6 +1,6 @@
1
1
  grctl/__init__.py,sha256=ovSyTyP0DJxBW_jC8CJrwYUs_BfXtMTnJqJ9qScZZyY,41
2
2
  grctl/client/__init__.py,sha256=FxY4a__J1SciqPTtouzQP8e76yRInchtrv_5OT9XoXc,259
3
- grctl/client/client.py,sha256=ByGsFGF2k64ybGZhKPMjznK0YrKTO1ajWnB29WDFO-o,3901
3
+ grctl/client/client.py,sha256=0ozm-sRz0kiV0U1VWJjNTCnd14uQJ4U_3Uk66JxGLZw,4510
4
4
  grctl/logging_config.py,sha256=OMoz3FRnxAwkE9BNDuFxFu8aRzURnXeU9-75xVXiomg,1457
5
5
  grctl/models/__init__.py,sha256=-E1nliiY_Esiz-8Pc3WkyT7eYoph0czLsl3Uz8n6P4w,2752
6
6
  grctl/models/api.py,sha256=xygDA8b0E5BeQSrtfu_RToTW7XB2XWEO3n-zbh4W4S8,288
@@ -8,25 +8,25 @@ grctl/models/command.py,sha256=SgnaAt2JNQOventxDU5C99-BAOB3WFhQADNsNfVhY54,2509
8
8
  grctl/models/common.py,sha256=XtqhHrgwIRlQGTEjrnsAfIPqajEpg9-4MkeSk87eemE,174
9
9
  grctl/models/directive.py,sha256=9N_v4YvI4Qew-_O4UHeBnQJ2HrDSkqo9uCflrCFltbY,4947
10
10
  grctl/models/errors.py,sha256=ckFlCRgmiYYWXqi22pY9cOIGRCgGXiG4FknhxjD4oqU,179
11
- grctl/models/history.py,sha256=JejABqORPrcPlonQMk6641AA_hHrwMIUaUEHF5qJ8j8,8046
11
+ grctl/models/history.py,sha256=O_DNZcKG70b169dxBFH3HFw8vTKj9BtKeLGHkQDBoO4,8121
12
12
  grctl/models/run_info.py,sha256=OFbZ6ms_G4fpNTuScm03VbaYHpmQUwRzofvIIre3Eu8,2134
13
13
  grctl/models/run_info_helper.py,sha256=WG_lydSwkwX8PFxWZ9vMZw18cwFyQks-50x8-vMOlcE,301
14
14
  grctl/models/worker.py,sha256=Av8HQoTkkPUjV0ztq_NckC-Rem57g4ssTFyu8JrqsQo,1889
15
15
  grctl/nats/__init__.py,sha256=QTrNaWbv4WV1gLKcQlbPufZYDNCkww42edwxBoHVE-8,37
16
16
  grctl/nats/connection.py,sha256=DIQ7jz0XXRGlTeuuvV-cq4iNDj06V397vGo44Pnyqdg,1878
17
- grctl/nats/history_fetch.py,sha256=pLKlPqeWD0zq3ieRrWaIbAGgEwzy7W1LooLdrJUjFyY,1440
17
+ grctl/nats/history_fetch.py,sha256=UuCWSe9jPP0Ry8HDePN_VOx0B07JNMxQmKpuxSxNTKY,2398
18
18
  grctl/nats/history_sub.py,sha256=E-t5loBTYNU5OH_8Xr4WFGFo3jrU9URbvBc-TxGSmxw,2198
19
19
  grctl/nats/kv_store.py,sha256=fYoigg3_GHryYrphf9OoA-3uyffPr-YDz4Dt5G1u5OQ,1307
20
20
  grctl/nats/manifest.py,sha256=NMxeuw5_j8WKqGdOp3DInGBLrYriye9RD3y4Ymr0mW8,9222
21
21
  grctl/nats/nats_client.py,sha256=3XK8K3_ix-3vcGnMXo_LAY2fn-14y8JVSjbFCF_6OC4,343
22
22
  grctl/nats/nats_manifest.yaml,sha256=FZXsJY3wqSNp3mhzh2awA_7NDq8OV8Mz0b2VK03T_dM,2661
23
23
  grctl/nats/publisher.py,sha256=-PCkfd4OIyjHa645oLuAGQyL3dy2bw0serMtmyF4f1o,1561
24
- grctl/nats/subscriber.py,sha256=Let9cuCv9qXK3rEf87KDPJUMdKh_Y4HpoxRg57ctaoQ,4468
24
+ grctl/nats/subscriber.py,sha256=0LG1CkR--fxPe5PuFTuFNEA1UoXupRvqvek2T0fpUQA,4436
25
25
  grctl/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
26
26
  grctl/settings.py,sha256=8O88vPcVzLHHv8JVxgNbwE3ErDqxjZf2_N4Tj35t7HM,601
27
27
  grctl/worker/__init__.py,sha256=dEnavSsxpbvAFonVcZiS-VPxtvgRneAp86XtuXqabiw,256
28
28
  grctl/worker/codec.py,sha256=ywioAv30GKxxAcAAbX7a3unFWpz9OBuzNXzy90i9iyw,1642
29
- grctl/worker/context.py,sha256=eImnSUUGr864cYpxyUiuwRnntwqfTo6F4jo_gumEY3g,10260
29
+ grctl/worker/context.py,sha256=IzKZFS0LBQVTwgkiRaGwhUdCZs_YQrcFW3sqz_oqfZs,10439
30
30
  grctl/worker/errors.py,sha256=QFFruX23v1r-Xnc6gihRfLaapnUSY9HMBPWq5lwjB_U,1239
31
31
  grctl/worker/logger.py,sha256=vjHxk03ro1rVvDP2l94lfg-2yeN_pUks4tbrEm52YyQ,1364
32
32
  grctl/worker/run_manager.py,sha256=F1jdGrt8KS7WoLIacz6uQizfhTLpGP-21NLCgN3P4sA,4751
@@ -34,12 +34,12 @@ grctl/worker/runner.py,sha256=icz-Q9SY3u4bma1iwzUaq6ifAo0E1QrWYBJknI495Ec,6866
34
34
  grctl/worker/runtime.py,sha256=MfuYfsV0aEhLmRqrPl4vdnOvLDsWhPpWnfp-nFEqgoY,6783
35
35
  grctl/worker/store.py,sha256=puLSeVV4RfWibELGsjdiztZcPBRRlIV1iupAaUr0JYs,1750
36
36
  grctl/worker/task.py,sha256=3FFbMiLdBTXAV2L6DI3kRfqYxXxu-0_mLUvieovh0TU,14487
37
- grctl/worker/worker.py,sha256=EFBZgA7QWjKAbVGZsAReAsvZzO0szuDjrbbDktwduOQ,5297
37
+ grctl/worker/worker.py,sha256=RfA2_TdRDEjoTU7Q_5sTnaxgnoZVIiY6wa3G1UiF5RA,6137
38
38
  grctl/workflow/__init__.py,sha256=vu0cIFdbSgH6PSU60keXN2jkkkGn4bSG3UyRpIsSJXU,287
39
- grctl/workflow/future.py,sha256=8XSwvBdAboa-1OW-oX1tg4fqTfzdxpmRpEWLCx5xu7I,5077
39
+ grctl/workflow/future.py,sha256=oIzTArOYTwTpzVZBxxBxBeSNvswVhqE6CvJhd_-ljKE,5585
40
40
  grctl/workflow/handle.py,sha256=3dRhwLHRSfO7-wvka3YL_JEkUJLvy2Lnr1dMXWwAsuE,2671
41
41
  grctl/workflow/workflow.py,sha256=jBdDBGjg6gE0t02CTN1-pBLk2DpMGEsk63TAuQXj7tQ,8602
42
- grctl_sdk_python-0.1.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
43
- grctl_sdk_python-0.1.2.dist-info/WHEEL,sha256=q5IF0q2xCp3ktUFRCVWsQLjl2ChNlWXBJtnI1LCGdJ8,80
44
- grctl_sdk_python-0.1.2.dist-info/METADATA,sha256=nKSIjvUX02HiLu-IC7a9MNz2oFakLgtebgZwfjXH5OA,2319
45
- grctl_sdk_python-0.1.2.dist-info/RECORD,,
42
+ grctl_sdk_python-0.1.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
43
+ grctl_sdk_python-0.1.3.dist-info/WHEEL,sha256=q5IF0q2xCp3ktUFRCVWsQLjl2ChNlWXBJtnI1LCGdJ8,80
44
+ grctl_sdk_python-0.1.3.dist-info/METADATA,sha256=tK61B6ZhJKVHMZURivXut8gXVajyAj7iFaeOMsk5m9g,2309
45
+ grctl_sdk_python-0.1.3.dist-info/RECORD,,