queueflow 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.
- queueflow/__init__.py +80 -0
- queueflow/api/__init__.py +11 -0
- queueflow/api/cron_api.py +1808 -0
- queueflow/api/dlq_api.py +996 -0
- queueflow/api/health_api.py +527 -0
- queueflow/api/jobs_api.py +1830 -0
- queueflow/api/system_api.py +523 -0
- queueflow/api/worker_api.py +1229 -0
- queueflow/api/workflows_api.py +1804 -0
- queueflow/api_client.py +797 -0
- queueflow/api_response.py +21 -0
- queueflow/configuration.py +579 -0
- queueflow/exceptions.py +199 -0
- queueflow/facade.py +255 -0
- queueflow/models/__init__.py +57 -0
- queueflow/models/backoff_strategy.py +38 -0
- queueflow/models/complete_job_request.py +89 -0
- queueflow/models/create_batch_jobs_request.py +95 -0
- queueflow/models/create_batch_jobs_response.py +90 -0
- queueflow/models/create_cron_request.py +111 -0
- queueflow/models/create_cron_response.py +87 -0
- queueflow/models/create_job_request.py +108 -0
- queueflow/models/create_job_response.py +87 -0
- queueflow/models/create_workflow_request.py +101 -0
- queueflow/models/create_workflow_response.py +87 -0
- queueflow/models/cron_schedule.py +134 -0
- queueflow/models/dead_letter.py +136 -0
- queueflow/models/error_body.py +90 -0
- queueflow/models/fail_job_request.py +91 -0
- queueflow/models/health_status.py +92 -0
- queueflow/models/heartbeat_request.py +90 -0
- queueflow/models/heartbeat_response.py +88 -0
- queueflow/models/job.py +172 -0
- queueflow/models/job_config.py +106 -0
- queueflow/models/job_config_request.py +143 -0
- queueflow/models/job_status.py +41 -0
- queueflow/models/lease_jobs_request.py +107 -0
- queueflow/models/lease_jobs_response.py +95 -0
- queueflow/models/leased_job.py +93 -0
- queueflow/models/list_crons_response.py +115 -0
- queueflow/models/list_dead_letters_response.py +115 -0
- queueflow/models/list_jobs_response.py +115 -0
- queueflow/models/list_workflows_response.py +115 -0
- queueflow/models/on_failure.py +38 -0
- queueflow/models/on_success.py +36 -0
- queueflow/models/ready_status.py +87 -0
- queueflow/models/replay_dead_letter_response.py +87 -0
- queueflow/models/stats_snapshot.py +102 -0
- queueflow/models/step_status.py +41 -0
- queueflow/models/tasks_response.py +87 -0
- queueflow/models/workflow.py +130 -0
- queueflow/models/workflow_diagram_response.py +89 -0
- queueflow/models/workflow_status.py +41 -0
- queueflow/models/workflow_step.py +112 -0
- queueflow/models/workflow_step_state.py +97 -0
- queueflow/models/workflow_step_states_response.py +95 -0
- queueflow/py.typed +0 -0
- queueflow/rest.py +257 -0
- queueflow-0.1.0.dist-info/METADATA +26 -0
- queueflow-0.1.0.dist-info/RECORD +62 -0
- queueflow-0.1.0.dist-info/WHEEL +5 -0
- queueflow-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
QueueFlow API
|
|
5
|
+
|
|
6
|
+
REST API for QueueFlow, a PostgreSQL-native distributed job queue and workflow engine.
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictStr
|
|
21
|
+
from typing import Any, ClassVar, Dict, List
|
|
22
|
+
from typing_extensions import Annotated
|
|
23
|
+
from typing import Optional, Set
|
|
24
|
+
from typing_extensions import Self
|
|
25
|
+
|
|
26
|
+
class HeartbeatRequest(BaseModel):
|
|
27
|
+
"""
|
|
28
|
+
Body for `POST /api/v1/jobs/{id}/heartbeat`.
|
|
29
|
+
""" # noqa: E501
|
|
30
|
+
extend_secs: Annotated[int, Field(strict=True, ge=0)] = Field(description="New lease duration in seconds, measured from now (1..=3600).")
|
|
31
|
+
lease_token: StrictStr = Field(description="The lease token returned by the lease call.")
|
|
32
|
+
__properties: ClassVar[List[str]] = ["extend_secs", "lease_token"]
|
|
33
|
+
|
|
34
|
+
model_config = ConfigDict(
|
|
35
|
+
populate_by_name=True,
|
|
36
|
+
validate_assignment=True,
|
|
37
|
+
protected_namespaces=(),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def to_str(self) -> str:
|
|
42
|
+
"""Returns the string representation of the model using alias"""
|
|
43
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
44
|
+
|
|
45
|
+
def to_json(self) -> str:
|
|
46
|
+
"""Returns the JSON representation of the model using alias"""
|
|
47
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
48
|
+
return json.dumps(self.to_dict())
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
52
|
+
"""Create an instance of HeartbeatRequest from a JSON string"""
|
|
53
|
+
return cls.from_dict(json.loads(json_str))
|
|
54
|
+
|
|
55
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
56
|
+
"""Return the dictionary representation of the model using alias.
|
|
57
|
+
|
|
58
|
+
This has the following differences from calling pydantic's
|
|
59
|
+
`self.model_dump(by_alias=True)`:
|
|
60
|
+
|
|
61
|
+
* `None` is only added to the output dict for nullable fields that
|
|
62
|
+
were set at model initialization. Other fields with value `None`
|
|
63
|
+
are ignored.
|
|
64
|
+
"""
|
|
65
|
+
excluded_fields: Set[str] = set([
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
_dict = self.model_dump(
|
|
69
|
+
by_alias=True,
|
|
70
|
+
exclude=excluded_fields,
|
|
71
|
+
exclude_none=True,
|
|
72
|
+
)
|
|
73
|
+
return _dict
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
77
|
+
"""Create an instance of HeartbeatRequest from a dict"""
|
|
78
|
+
if obj is None:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
if not isinstance(obj, dict):
|
|
82
|
+
return cls.model_validate(obj)
|
|
83
|
+
|
|
84
|
+
_obj = cls.model_validate({
|
|
85
|
+
"extend_secs": obj.get("extend_secs"),
|
|
86
|
+
"lease_token": obj.get("lease_token")
|
|
87
|
+
})
|
|
88
|
+
return _obj
|
|
89
|
+
|
|
90
|
+
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
QueueFlow API
|
|
5
|
+
|
|
6
|
+
REST API for QueueFlow, a PostgreSQL-native distributed job queue and workflow engine.
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
21
|
+
from typing import Any, ClassVar, Dict, List
|
|
22
|
+
from queueflow.models.job_status import JobStatus
|
|
23
|
+
from typing import Optional, Set
|
|
24
|
+
from typing_extensions import Self
|
|
25
|
+
|
|
26
|
+
class HeartbeatResponse(BaseModel):
|
|
27
|
+
"""
|
|
28
|
+
Response for `POST /api/v1/jobs/{id}/heartbeat`.
|
|
29
|
+
""" # noqa: E501
|
|
30
|
+
status: JobStatus = Field(description="The job's current status. `running` means the lease was extended; anything else (`cancelled`, `completed`, ...) means it was not, and the worker should stop working on the job.")
|
|
31
|
+
__properties: ClassVar[List[str]] = ["status"]
|
|
32
|
+
|
|
33
|
+
model_config = ConfigDict(
|
|
34
|
+
populate_by_name=True,
|
|
35
|
+
validate_assignment=True,
|
|
36
|
+
protected_namespaces=(),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def to_str(self) -> str:
|
|
41
|
+
"""Returns the string representation of the model using alias"""
|
|
42
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
43
|
+
|
|
44
|
+
def to_json(self) -> str:
|
|
45
|
+
"""Returns the JSON representation of the model using alias"""
|
|
46
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
47
|
+
return json.dumps(self.to_dict())
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
51
|
+
"""Create an instance of HeartbeatResponse from a JSON string"""
|
|
52
|
+
return cls.from_dict(json.loads(json_str))
|
|
53
|
+
|
|
54
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
55
|
+
"""Return the dictionary representation of the model using alias.
|
|
56
|
+
|
|
57
|
+
This has the following differences from calling pydantic's
|
|
58
|
+
`self.model_dump(by_alias=True)`:
|
|
59
|
+
|
|
60
|
+
* `None` is only added to the output dict for nullable fields that
|
|
61
|
+
were set at model initialization. Other fields with value `None`
|
|
62
|
+
are ignored.
|
|
63
|
+
"""
|
|
64
|
+
excluded_fields: Set[str] = set([
|
|
65
|
+
])
|
|
66
|
+
|
|
67
|
+
_dict = self.model_dump(
|
|
68
|
+
by_alias=True,
|
|
69
|
+
exclude=excluded_fields,
|
|
70
|
+
exclude_none=True,
|
|
71
|
+
)
|
|
72
|
+
return _dict
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
76
|
+
"""Create an instance of HeartbeatResponse from a dict"""
|
|
77
|
+
if obj is None:
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
if not isinstance(obj, dict):
|
|
81
|
+
return cls.model_validate(obj)
|
|
82
|
+
|
|
83
|
+
_obj = cls.model_validate({
|
|
84
|
+
"status": obj.get("status")
|
|
85
|
+
})
|
|
86
|
+
return _obj
|
|
87
|
+
|
|
88
|
+
|
queueflow/models/job.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
QueueFlow API
|
|
5
|
+
|
|
6
|
+
REST API for QueueFlow, a PostgreSQL-native distributed job queue and workflow engine.
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictStr
|
|
22
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
23
|
+
from typing_extensions import Annotated
|
|
24
|
+
from queueflow.models.job_config import JobConfig
|
|
25
|
+
from queueflow.models.job_status import JobStatus
|
|
26
|
+
from typing import Optional, Set
|
|
27
|
+
from typing_extensions import Self
|
|
28
|
+
|
|
29
|
+
class Job(BaseModel):
|
|
30
|
+
"""
|
|
31
|
+
A single unit of work.
|
|
32
|
+
""" # noqa: E501
|
|
33
|
+
completed_at: Optional[datetime] = None
|
|
34
|
+
config: JobConfig
|
|
35
|
+
created_at: datetime
|
|
36
|
+
delivery_count: Optional[Annotated[int, Field(strict=True, ge=0)]] = Field(default=None, description="How many times this job has been claimed (delivered to a worker). Greater than `retry_count + 1` means a lease expired without a report — i.e. a worker crashed mid-run.")
|
|
37
|
+
error_message: Optional[StrictStr] = None
|
|
38
|
+
id: StrictStr
|
|
39
|
+
idempotency_key: Optional[StrictStr] = Field(default=None, description="Client-supplied key that makes job creation idempotent per tenant: re-submitting the same key returns the original job instead of creating a duplicate.")
|
|
40
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
41
|
+
next_retry_at: Optional[datetime] = Field(default=None, description="When this job's next retry becomes claimable (mirrors `scheduled_at` while the job is `retrying`; kept for audit/inspection).")
|
|
42
|
+
payload: Optional[Dict[str, Any]] = None
|
|
43
|
+
queue_name: StrictStr
|
|
44
|
+
result: Optional[Dict[str, Any]] = None
|
|
45
|
+
retry_count: Annotated[int, Field(strict=True, ge=0)]
|
|
46
|
+
scheduled_at: datetime = Field(description="When the job becomes claimable. `created_at` for immediate jobs, the requested `run_at` for scheduled jobs, and the next backoff instant while retrying — the durable delay lives in the row itself.")
|
|
47
|
+
started_at: Optional[datetime] = None
|
|
48
|
+
status: JobStatus
|
|
49
|
+
task_name: StrictStr
|
|
50
|
+
tenant_id: Optional[StrictStr] = None
|
|
51
|
+
workflow_id: Optional[StrictStr] = None
|
|
52
|
+
workflow_step_id: Optional[StrictStr] = Field(default=None, description="The owning workflow step's name (steps are addressed by name).")
|
|
53
|
+
__properties: ClassVar[List[str]] = ["completed_at", "config", "created_at", "delivery_count", "error_message", "id", "idempotency_key", "metadata", "next_retry_at", "payload", "queue_name", "result", "retry_count", "scheduled_at", "started_at", "status", "task_name", "tenant_id", "workflow_id", "workflow_step_id"]
|
|
54
|
+
|
|
55
|
+
model_config = ConfigDict(
|
|
56
|
+
populate_by_name=True,
|
|
57
|
+
validate_assignment=True,
|
|
58
|
+
protected_namespaces=(),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def to_str(self) -> str:
|
|
63
|
+
"""Returns the string representation of the model using alias"""
|
|
64
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
65
|
+
|
|
66
|
+
def to_json(self) -> str:
|
|
67
|
+
"""Returns the JSON representation of the model using alias"""
|
|
68
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
69
|
+
return json.dumps(self.to_dict())
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
73
|
+
"""Create an instance of Job from a JSON string"""
|
|
74
|
+
return cls.from_dict(json.loads(json_str))
|
|
75
|
+
|
|
76
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
77
|
+
"""Return the dictionary representation of the model using alias.
|
|
78
|
+
|
|
79
|
+
This has the following differences from calling pydantic's
|
|
80
|
+
`self.model_dump(by_alias=True)`:
|
|
81
|
+
|
|
82
|
+
* `None` is only added to the output dict for nullable fields that
|
|
83
|
+
were set at model initialization. Other fields with value `None`
|
|
84
|
+
are ignored.
|
|
85
|
+
"""
|
|
86
|
+
excluded_fields: Set[str] = set([
|
|
87
|
+
])
|
|
88
|
+
|
|
89
|
+
_dict = self.model_dump(
|
|
90
|
+
by_alias=True,
|
|
91
|
+
exclude=excluded_fields,
|
|
92
|
+
exclude_none=True,
|
|
93
|
+
)
|
|
94
|
+
# override the default output from pydantic by calling `to_dict()` of config
|
|
95
|
+
if self.config:
|
|
96
|
+
_dict['config'] = self.config.to_dict()
|
|
97
|
+
# set to None if completed_at (nullable) is None
|
|
98
|
+
# and model_fields_set contains the field
|
|
99
|
+
if self.completed_at is None and "completed_at" in self.model_fields_set:
|
|
100
|
+
_dict['completed_at'] = None
|
|
101
|
+
|
|
102
|
+
# set to None if error_message (nullable) is None
|
|
103
|
+
# and model_fields_set contains the field
|
|
104
|
+
if self.error_message is None and "error_message" in self.model_fields_set:
|
|
105
|
+
_dict['error_message'] = None
|
|
106
|
+
|
|
107
|
+
# set to None if idempotency_key (nullable) is None
|
|
108
|
+
# and model_fields_set contains the field
|
|
109
|
+
if self.idempotency_key is None and "idempotency_key" in self.model_fields_set:
|
|
110
|
+
_dict['idempotency_key'] = None
|
|
111
|
+
|
|
112
|
+
# set to None if next_retry_at (nullable) is None
|
|
113
|
+
# and model_fields_set contains the field
|
|
114
|
+
if self.next_retry_at is None and "next_retry_at" in self.model_fields_set:
|
|
115
|
+
_dict['next_retry_at'] = None
|
|
116
|
+
|
|
117
|
+
# set to None if started_at (nullable) is None
|
|
118
|
+
# and model_fields_set contains the field
|
|
119
|
+
if self.started_at is None and "started_at" in self.model_fields_set:
|
|
120
|
+
_dict['started_at'] = None
|
|
121
|
+
|
|
122
|
+
# set to None if tenant_id (nullable) is None
|
|
123
|
+
# and model_fields_set contains the field
|
|
124
|
+
if self.tenant_id is None and "tenant_id" in self.model_fields_set:
|
|
125
|
+
_dict['tenant_id'] = None
|
|
126
|
+
|
|
127
|
+
# set to None if workflow_id (nullable) is None
|
|
128
|
+
# and model_fields_set contains the field
|
|
129
|
+
if self.workflow_id is None and "workflow_id" in self.model_fields_set:
|
|
130
|
+
_dict['workflow_id'] = None
|
|
131
|
+
|
|
132
|
+
# set to None if workflow_step_id (nullable) is None
|
|
133
|
+
# and model_fields_set contains the field
|
|
134
|
+
if self.workflow_step_id is None and "workflow_step_id" in self.model_fields_set:
|
|
135
|
+
_dict['workflow_step_id'] = None
|
|
136
|
+
|
|
137
|
+
return _dict
|
|
138
|
+
|
|
139
|
+
@classmethod
|
|
140
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
141
|
+
"""Create an instance of Job from a dict"""
|
|
142
|
+
if obj is None:
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
if not isinstance(obj, dict):
|
|
146
|
+
return cls.model_validate(obj)
|
|
147
|
+
|
|
148
|
+
_obj = cls.model_validate({
|
|
149
|
+
"completed_at": obj.get("completed_at"),
|
|
150
|
+
"config": JobConfig.from_dict(obj["config"]) if obj.get("config") is not None else None,
|
|
151
|
+
"created_at": obj.get("created_at"),
|
|
152
|
+
"delivery_count": obj.get("delivery_count"),
|
|
153
|
+
"error_message": obj.get("error_message"),
|
|
154
|
+
"id": obj.get("id"),
|
|
155
|
+
"idempotency_key": obj.get("idempotency_key"),
|
|
156
|
+
"metadata": obj.get("metadata"),
|
|
157
|
+
"next_retry_at": obj.get("next_retry_at"),
|
|
158
|
+
"payload": obj.get("payload"),
|
|
159
|
+
"queue_name": obj.get("queue_name"),
|
|
160
|
+
"result": obj.get("result"),
|
|
161
|
+
"retry_count": obj.get("retry_count"),
|
|
162
|
+
"scheduled_at": obj.get("scheduled_at"),
|
|
163
|
+
"started_at": obj.get("started_at"),
|
|
164
|
+
"status": obj.get("status"),
|
|
165
|
+
"task_name": obj.get("task_name"),
|
|
166
|
+
"tenant_id": obj.get("tenant_id"),
|
|
167
|
+
"workflow_id": obj.get("workflow_id"),
|
|
168
|
+
"workflow_step_id": obj.get("workflow_step_id")
|
|
169
|
+
})
|
|
170
|
+
return _obj
|
|
171
|
+
|
|
172
|
+
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
QueueFlow API
|
|
5
|
+
|
|
6
|
+
REST API for QueueFlow, a PostgreSQL-native distributed job queue and workflow engine.
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt
|
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional, Union
|
|
22
|
+
from typing_extensions import Annotated
|
|
23
|
+
from queueflow.models.backoff_strategy import BackoffStrategy
|
|
24
|
+
from typing import Optional, Set
|
|
25
|
+
from typing_extensions import Self
|
|
26
|
+
|
|
27
|
+
class JobConfig(BaseModel):
|
|
28
|
+
"""
|
|
29
|
+
Per-job execution configuration. All durations are in seconds. Deserialization is partial-friendly: any omitted field takes its [`JobConfig::default`] value (via per-field serde defaults), so workflow-step and cron config overrides can name just the fields they change, and out-of-band rows with sparse `config` JSONB still load. Per-field functions rather than a struct-level `#[serde(default)]`: the struct-level form makes utoipa attach a `default` beside the `BackoffStrategy` `$ref`, which forces a synthetic wrapper type into every generated SDK.
|
|
30
|
+
""" # noqa: E501
|
|
31
|
+
jitter_factor: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="Optional jitter in `0.0..=1.0`. `0.1` => +/-10% randomization of each retry delay, which spreads out thundering-herd retries.")
|
|
32
|
+
max_retries: Optional[Annotated[int, Field(strict=True, ge=0)]] = None
|
|
33
|
+
priority: Optional[StrictInt] = Field(default=None, description="Higher is claimed first within a queue; ties break on `scheduled_at`, then `created_at`.")
|
|
34
|
+
retry_backoff: Optional[BackoffStrategy] = None
|
|
35
|
+
retry_delay_secs: Optional[Annotated[int, Field(strict=True, ge=0)]] = None
|
|
36
|
+
retry_max_delay_secs: Optional[Annotated[int, Field(strict=True, ge=0)]] = None
|
|
37
|
+
timeout_secs: Optional[Annotated[int, Field(strict=True, ge=0)]] = None
|
|
38
|
+
__properties: ClassVar[List[str]] = ["jitter_factor", "max_retries", "priority", "retry_backoff", "retry_delay_secs", "retry_max_delay_secs", "timeout_secs"]
|
|
39
|
+
|
|
40
|
+
model_config = ConfigDict(
|
|
41
|
+
populate_by_name=True,
|
|
42
|
+
validate_assignment=True,
|
|
43
|
+
protected_namespaces=(),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def to_str(self) -> str:
|
|
48
|
+
"""Returns the string representation of the model using alias"""
|
|
49
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
50
|
+
|
|
51
|
+
def to_json(self) -> str:
|
|
52
|
+
"""Returns the JSON representation of the model using alias"""
|
|
53
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
54
|
+
return json.dumps(self.to_dict())
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
58
|
+
"""Create an instance of JobConfig from a JSON string"""
|
|
59
|
+
return cls.from_dict(json.loads(json_str))
|
|
60
|
+
|
|
61
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
62
|
+
"""Return the dictionary representation of the model using alias.
|
|
63
|
+
|
|
64
|
+
This has the following differences from calling pydantic's
|
|
65
|
+
`self.model_dump(by_alias=True)`:
|
|
66
|
+
|
|
67
|
+
* `None` is only added to the output dict for nullable fields that
|
|
68
|
+
were set at model initialization. Other fields with value `None`
|
|
69
|
+
are ignored.
|
|
70
|
+
"""
|
|
71
|
+
excluded_fields: Set[str] = set([
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
_dict = self.model_dump(
|
|
75
|
+
by_alias=True,
|
|
76
|
+
exclude=excluded_fields,
|
|
77
|
+
exclude_none=True,
|
|
78
|
+
)
|
|
79
|
+
# set to None if jitter_factor (nullable) is None
|
|
80
|
+
# and model_fields_set contains the field
|
|
81
|
+
if self.jitter_factor is None and "jitter_factor" in self.model_fields_set:
|
|
82
|
+
_dict['jitter_factor'] = None
|
|
83
|
+
|
|
84
|
+
return _dict
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
88
|
+
"""Create an instance of JobConfig from a dict"""
|
|
89
|
+
if obj is None:
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
if not isinstance(obj, dict):
|
|
93
|
+
return cls.model_validate(obj)
|
|
94
|
+
|
|
95
|
+
_obj = cls.model_validate({
|
|
96
|
+
"jitter_factor": obj.get("jitter_factor"),
|
|
97
|
+
"max_retries": obj.get("max_retries"),
|
|
98
|
+
"priority": obj.get("priority"),
|
|
99
|
+
"retry_backoff": obj.get("retry_backoff"),
|
|
100
|
+
"retry_delay_secs": obj.get("retry_delay_secs"),
|
|
101
|
+
"retry_max_delay_secs": obj.get("retry_max_delay_secs"),
|
|
102
|
+
"timeout_secs": obj.get("timeout_secs")
|
|
103
|
+
})
|
|
104
|
+
return _obj
|
|
105
|
+
|
|
106
|
+
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
QueueFlow API
|
|
5
|
+
|
|
6
|
+
REST API for QueueFlow, a PostgreSQL-native distributed job queue and workflow engine.
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import pprint
|
|
17
|
+
import re # noqa: F401
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr
|
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional, Union
|
|
22
|
+
from typing_extensions import Annotated
|
|
23
|
+
from queueflow.models.backoff_strategy import BackoffStrategy
|
|
24
|
+
from typing import Optional, Set
|
|
25
|
+
from typing_extensions import Self
|
|
26
|
+
|
|
27
|
+
class JobConfigRequest(BaseModel):
|
|
28
|
+
"""
|
|
29
|
+
Optional per-job configuration overrides.
|
|
30
|
+
""" # noqa: E501
|
|
31
|
+
jitter_factor: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="Retry-delay jitter in `0.0..=1.0` (e.g. `0.1` = +/-10%).")
|
|
32
|
+
max_retries: Optional[Annotated[int, Field(strict=True, ge=0)]] = None
|
|
33
|
+
priority: Optional[StrictInt] = Field(default=None, description="Higher is claimed first within a queue (ties: oldest first).")
|
|
34
|
+
queue: Optional[StrictStr] = Field(default=None, description="Override the destination queue.")
|
|
35
|
+
retry_backoff: Optional[BackoffStrategy] = Field(default=None, description="How retry delays grow between attempts (default exponential).")
|
|
36
|
+
retry_delay_secs: Optional[Annotated[int, Field(strict=True, ge=0)]] = Field(default=None, description="Base retry delay, in seconds.")
|
|
37
|
+
retry_max_delay_secs: Optional[Annotated[int, Field(strict=True, ge=0)]] = Field(default=None, description="Upper bound on any computed retry delay, in seconds.")
|
|
38
|
+
timeout: Optional[Annotated[int, Field(strict=True, ge=0)]] = Field(default=None, description="Per-attempt timeout, in seconds.")
|
|
39
|
+
__properties: ClassVar[List[str]] = ["jitter_factor", "max_retries", "priority", "queue", "retry_backoff", "retry_delay_secs", "retry_max_delay_secs", "timeout"]
|
|
40
|
+
|
|
41
|
+
model_config = ConfigDict(
|
|
42
|
+
populate_by_name=True,
|
|
43
|
+
validate_assignment=True,
|
|
44
|
+
protected_namespaces=(),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def to_str(self) -> str:
|
|
49
|
+
"""Returns the string representation of the model using alias"""
|
|
50
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
|
51
|
+
|
|
52
|
+
def to_json(self) -> str:
|
|
53
|
+
"""Returns the JSON representation of the model using alias"""
|
|
54
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
|
55
|
+
return json.dumps(self.to_dict())
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
|
59
|
+
"""Create an instance of JobConfigRequest from a JSON string"""
|
|
60
|
+
return cls.from_dict(json.loads(json_str))
|
|
61
|
+
|
|
62
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
63
|
+
"""Return the dictionary representation of the model using alias.
|
|
64
|
+
|
|
65
|
+
This has the following differences from calling pydantic's
|
|
66
|
+
`self.model_dump(by_alias=True)`:
|
|
67
|
+
|
|
68
|
+
* `None` is only added to the output dict for nullable fields that
|
|
69
|
+
were set at model initialization. Other fields with value `None`
|
|
70
|
+
are ignored.
|
|
71
|
+
"""
|
|
72
|
+
excluded_fields: Set[str] = set([
|
|
73
|
+
])
|
|
74
|
+
|
|
75
|
+
_dict = self.model_dump(
|
|
76
|
+
by_alias=True,
|
|
77
|
+
exclude=excluded_fields,
|
|
78
|
+
exclude_none=True,
|
|
79
|
+
)
|
|
80
|
+
# set to None if jitter_factor (nullable) is None
|
|
81
|
+
# and model_fields_set contains the field
|
|
82
|
+
if self.jitter_factor is None and "jitter_factor" in self.model_fields_set:
|
|
83
|
+
_dict['jitter_factor'] = None
|
|
84
|
+
|
|
85
|
+
# set to None if max_retries (nullable) is None
|
|
86
|
+
# and model_fields_set contains the field
|
|
87
|
+
if self.max_retries is None and "max_retries" in self.model_fields_set:
|
|
88
|
+
_dict['max_retries'] = None
|
|
89
|
+
|
|
90
|
+
# set to None if priority (nullable) is None
|
|
91
|
+
# and model_fields_set contains the field
|
|
92
|
+
if self.priority is None and "priority" in self.model_fields_set:
|
|
93
|
+
_dict['priority'] = None
|
|
94
|
+
|
|
95
|
+
# set to None if queue (nullable) is None
|
|
96
|
+
# and model_fields_set contains the field
|
|
97
|
+
if self.queue is None and "queue" in self.model_fields_set:
|
|
98
|
+
_dict['queue'] = None
|
|
99
|
+
|
|
100
|
+
# set to None if retry_backoff (nullable) is None
|
|
101
|
+
# and model_fields_set contains the field
|
|
102
|
+
if self.retry_backoff is None and "retry_backoff" in self.model_fields_set:
|
|
103
|
+
_dict['retry_backoff'] = None
|
|
104
|
+
|
|
105
|
+
# set to None if retry_delay_secs (nullable) is None
|
|
106
|
+
# and model_fields_set contains the field
|
|
107
|
+
if self.retry_delay_secs is None and "retry_delay_secs" in self.model_fields_set:
|
|
108
|
+
_dict['retry_delay_secs'] = None
|
|
109
|
+
|
|
110
|
+
# set to None if retry_max_delay_secs (nullable) is None
|
|
111
|
+
# and model_fields_set contains the field
|
|
112
|
+
if self.retry_max_delay_secs is None and "retry_max_delay_secs" in self.model_fields_set:
|
|
113
|
+
_dict['retry_max_delay_secs'] = None
|
|
114
|
+
|
|
115
|
+
# set to None if timeout (nullable) is None
|
|
116
|
+
# and model_fields_set contains the field
|
|
117
|
+
if self.timeout is None and "timeout" in self.model_fields_set:
|
|
118
|
+
_dict['timeout'] = None
|
|
119
|
+
|
|
120
|
+
return _dict
|
|
121
|
+
|
|
122
|
+
@classmethod
|
|
123
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
|
124
|
+
"""Create an instance of JobConfigRequest from a dict"""
|
|
125
|
+
if obj is None:
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
if not isinstance(obj, dict):
|
|
129
|
+
return cls.model_validate(obj)
|
|
130
|
+
|
|
131
|
+
_obj = cls.model_validate({
|
|
132
|
+
"jitter_factor": obj.get("jitter_factor"),
|
|
133
|
+
"max_retries": obj.get("max_retries"),
|
|
134
|
+
"priority": obj.get("priority"),
|
|
135
|
+
"queue": obj.get("queue"),
|
|
136
|
+
"retry_backoff": obj.get("retry_backoff"),
|
|
137
|
+
"retry_delay_secs": obj.get("retry_delay_secs"),
|
|
138
|
+
"retry_max_delay_secs": obj.get("retry_max_delay_secs"),
|
|
139
|
+
"timeout": obj.get("timeout")
|
|
140
|
+
})
|
|
141
|
+
return _obj
|
|
142
|
+
|
|
143
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
QueueFlow API
|
|
5
|
+
|
|
6
|
+
REST API for QueueFlow, a PostgreSQL-native distributed job queue and workflow engine.
|
|
7
|
+
|
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
10
|
+
|
|
11
|
+
Do not edit the class manually.
|
|
12
|
+
""" # noqa: E501
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
import json
|
|
17
|
+
from enum import Enum
|
|
18
|
+
from typing_extensions import Self
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class JobStatus(str, Enum):
|
|
22
|
+
"""
|
|
23
|
+
Lifecycle state of a single job.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
allowed enum values
|
|
28
|
+
"""
|
|
29
|
+
PENDING = 'pending'
|
|
30
|
+
RUNNING = 'running'
|
|
31
|
+
COMPLETED = 'completed'
|
|
32
|
+
FAILED = 'failed'
|
|
33
|
+
RETRYING = 'retrying'
|
|
34
|
+
CANCELLED = 'cancelled'
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_json(cls, json_str: str) -> Self:
|
|
38
|
+
"""Create an instance of JobStatus from a JSON string"""
|
|
39
|
+
return cls(json.loads(json_str))
|
|
40
|
+
|
|
41
|
+
|