Skip to content

Commit 73eef62

Browse files
snopokeclaude
andcommitted
Add external_id to Task API and SDK
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent c35df8a commit 73eef62

6 files changed

Lines changed: 82 additions & 0 deletions

File tree

taskbadger.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,11 @@ components:
694694
type: string
695695
description: Queue the task is from
696696
maxLength: 255
697+
external_id:
698+
type: string
699+
description: Identifier from the originating system (e.g. Celery task ID)
700+
for correlating with logs
701+
maxLength: 255
697702
status:
698703
allOf:
699704
- $ref: '#/components/schemas/StatusEnum'
@@ -794,6 +799,11 @@ components:
794799
type: string
795800
description: Queue the task is from
796801
maxLength: 255
802+
external_id:
803+
type: string
804+
description: Identifier from the originating system (e.g. Celery task ID)
805+
for correlating with logs
806+
maxLength: 255
797807
status:
798808
allOf:
799809
- $ref: '#/components/schemas/StatusEnum'
@@ -893,6 +903,11 @@ components:
893903
type: string
894904
description: Queue the task is from
895905
maxLength: 255
906+
external_id:
907+
type: string
908+
description: Identifier from the originating system (e.g. Celery task ID)
909+
for correlating with logs
910+
maxLength: 255
896911
status:
897912
allOf:
898913
- $ref: '#/components/schemas/StatusEnum'

taskbadger/internal/models/patched_task_request.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class PatchedTaskRequest:
2424
Attributes:
2525
name (str | Unset): Name of the task
2626
queue (str | Unset): Queue the task is from
27+
external_id (str | Unset): Identifier from the originating system (e.g. Celery task ID) for correlating with
28+
logs
2729
status (StatusEnum | Unset): * `pending` - pending
2830
* `pre_processing` - pre_processing
2931
* `processing` - processing
@@ -50,6 +52,7 @@ class PatchedTaskRequest:
5052

5153
name: str | Unset = UNSET
5254
queue: str | Unset = UNSET
55+
external_id: str | Unset = UNSET
5356
status: StatusEnum | Unset = StatusEnum.PENDING
5457
value: int | None | Unset = UNSET
5558
value_max: int | Unset = UNSET
@@ -69,6 +72,8 @@ def to_dict(self) -> dict[str, Any]:
6972

7073
queue = self.queue
7174

75+
external_id = self.external_id
76+
7277
status: str | Unset = UNSET
7378
if not isinstance(self.status, Unset):
7479
status = self.status.value
@@ -128,6 +133,8 @@ def to_dict(self) -> dict[str, Any]:
128133
field_dict["name"] = name
129134
if queue is not UNSET:
130135
field_dict["queue"] = queue
136+
if external_id is not UNSET:
137+
field_dict["external_id"] = external_id
131138
if status is not UNSET:
132139
field_dict["status"] = status
133140
if value is not UNSET:
@@ -160,6 +167,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
160167

161168
queue = d.pop("queue", UNSET)
162169

170+
external_id = d.pop("external_id", UNSET)
171+
163172
_status = d.pop("status", UNSET)
164173
status: StatusEnum | Unset
165174
if isinstance(_status, Unset):
@@ -251,6 +260,7 @@ def _parse_stale_timeout(data: object) -> int | None | Unset:
251260
patched_task_request = cls(
252261
name=name,
253262
queue=queue,
263+
external_id=external_id,
254264
status=status,
255265
value=value,
256266
value_max=value_max,

taskbadger/internal/models/task.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class Task:
3232
url (str):
3333
public_url (str):
3434
queue (str | Unset): Queue the task is from
35+
external_id (str | Unset): Identifier from the originating system (e.g. Celery task ID) for correlating with
36+
logs
3537
status (StatusEnum | Unset): * `pending` - pending
3638
* `pre_processing` - pre_processing
3739
* `processing` - processing
@@ -66,6 +68,7 @@ class Task:
6668
url: str
6769
public_url: str
6870
queue: str | Unset = UNSET
71+
external_id: str | Unset = UNSET
6972
status: StatusEnum | Unset = StatusEnum.PENDING
7073
value: int | None | Unset = UNSET
7174
value_max: int | Unset = UNSET
@@ -102,6 +105,8 @@ def to_dict(self) -> dict[str, Any]:
102105

103106
queue = self.queue
104107

108+
external_id = self.external_id
109+
105110
status: str | Unset = UNSET
106111
if not isinstance(self.status, Unset):
107112
status = self.status.value
@@ -171,6 +176,8 @@ def to_dict(self) -> dict[str, Any]:
171176
)
172177
if queue is not UNSET:
173178
field_dict["queue"] = queue
179+
if external_id is not UNSET:
180+
field_dict["external_id"] = external_id
174181
if status is not UNSET:
175182
field_dict["status"] = status
176183
if value is not UNSET:
@@ -224,6 +231,8 @@ def _parse_value_percent(data: object) -> int | None:
224231

225232
queue = d.pop("queue", UNSET)
226233

234+
external_id = d.pop("external_id", UNSET)
235+
227236
_status = d.pop("status", UNSET)
228237
status: StatusEnum | Unset
229238
if isinstance(_status, Unset):
@@ -323,6 +332,7 @@ def _parse_stale_timeout(data: object) -> int | None | Unset:
323332
url=url,
324333
public_url=public_url,
325334
queue=queue,
335+
external_id=external_id,
326336
status=status,
327337
value=value,
328338
value_max=value_max,

taskbadger/internal/models/task_request.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class TaskRequest:
2424
Attributes:
2525
name (str): Name of the task
2626
queue (str | Unset): Queue the task is from
27+
external_id (str | Unset): Identifier from the originating system (e.g. Celery task ID) for correlating with
28+
logs
2729
status (StatusEnum | Unset): * `pending` - pending
2830
* `pre_processing` - pre_processing
2931
* `processing` - processing
@@ -50,6 +52,7 @@ class TaskRequest:
5052

5153
name: str
5254
queue: str | Unset = UNSET
55+
external_id: str | Unset = UNSET
5356
status: StatusEnum | Unset = StatusEnum.PENDING
5457
value: int | None | Unset = UNSET
5558
value_max: int | Unset = UNSET
@@ -69,6 +72,8 @@ def to_dict(self) -> dict[str, Any]:
6972

7073
queue = self.queue
7174

75+
external_id = self.external_id
76+
7277
status: str | Unset = UNSET
7378
if not isinstance(self.status, Unset):
7479
status = self.status.value
@@ -130,6 +135,8 @@ def to_dict(self) -> dict[str, Any]:
130135
)
131136
if queue is not UNSET:
132137
field_dict["queue"] = queue
138+
if external_id is not UNSET:
139+
field_dict["external_id"] = external_id
133140
if status is not UNSET:
134141
field_dict["status"] = status
135142
if value is not UNSET:
@@ -162,6 +169,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
162169

163170
queue = d.pop("queue", UNSET)
164171

172+
external_id = d.pop("external_id", UNSET)
173+
165174
_status = d.pop("status", UNSET)
166175
status: StatusEnum | Unset
167176
if isinstance(_status, Unset):
@@ -253,6 +262,7 @@ def _parse_stale_timeout(data: object) -> int | None | Unset:
253262
task_request = cls(
254263
name=name,
255264
queue=queue,
265+
external_id=external_id,
256266
status=status,
257267
value=value,
258268
value_max=value_max,

taskbadger/sdk.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ def create_task(
152152
monitor_id: str = None,
153153
tags: dict[str, str] = None,
154154
queue: str = None,
155+
external_id: str = None,
155156
) -> "Task":
156157
"""Create a Task.
157158
@@ -167,6 +168,7 @@ def create_task(
167168
monitor_id: ID of the monitor to associate this task with.
168169
tags: Dictionary of namespace -> value tags.
169170
queue: Name of the queue the task is from.
171+
external_id: Identifier from the originating system (e.g. Celery task ID) for correlating with logs.
170172
171173
Returns:
172174
Task: The created Task object.
@@ -177,6 +179,8 @@ def create_task(
177179
}
178180
if queue is not None:
179181
task_dict["queue"] = queue
182+
if external_id is not None:
183+
task_dict["external_id"] = external_id
180184
if value is not None:
181185
task_dict["value"] = value
182186
if value_max is not None:
@@ -222,6 +226,7 @@ def update_task(
222226
actions: list[Action] = None,
223227
tags: dict[str, str] = None,
224228
queue: str = None,
229+
external_id: str = None,
225230
) -> "Task":
226231
"""Update a task.
227232
Requires only the task ID and fields to update.
@@ -238,6 +243,7 @@ def update_task(
238243
actions: Task actions. **Deprecated:** use project-level actions instead.
239244
tags: Dictionary of namespace -> value tags.
240245
queue: Name of the queue the task is from.
246+
external_id: Identifier from the originating system (e.g. Celery task ID) for correlating with logs.
241247
242248
Returns:
243249
Task: The updated Task object.
@@ -250,6 +256,7 @@ def update_task(
250256
max_runtime = _none_to_unset(max_runtime)
251257
stale_timeout = _none_to_unset(stale_timeout)
252258
queue = _none_to_unset(queue)
259+
external_id = _none_to_unset(external_id)
253260

254261
data = data or UNSET
255262
body = PatchedTaskRequest(
@@ -261,6 +268,7 @@ def update_task(
261268
max_runtime=max_runtime,
262269
stale_timeout=stale_timeout,
263270
queue=queue,
271+
external_id=external_id,
264272
)
265273
if actions:
266274
_warn_actions_deprecated()
@@ -335,6 +343,7 @@ def create(
335343
monitor_id: str = None,
336344
tags: dict[str, str] = None,
337345
queue: str = None,
346+
external_id: str = None,
338347
) -> "Task":
339348
"""Create a new task
340349
@@ -352,6 +361,7 @@ def create(
352361
monitor_id=monitor_id,
353362
tags=tags,
354363
queue=queue,
364+
external_id=external_id,
355365
)
356366

357367
def __init__(self, task):
@@ -437,6 +447,7 @@ def update(
437447
actions: list[Action] = None,
438448
tags: dict[str, str] = None,
439449
queue: str = None,
450+
external_id: str = None,
440451
data_merge_strategy: Any = None,
441452
):
442453
"""Generic update method used to update any of the task fields.
@@ -465,6 +476,7 @@ def update(
465476
actions=actions,
466477
tags=tags,
467478
queue=queue,
479+
external_id=external_id,
468480
)
469481
self._task = task._task
470482

tests/test_sdk.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,31 @@ def test_update_queue(settings, patched_update):
124124
_verify_update(settings, patched_update, queue="high_priority")
125125

126126

127+
def test_create_with_external_id(settings, patched_create):
128+
api_task = task_for_test()
129+
patched_create.return_value = Response(HTTPStatus.OK, b"", {}, api_task)
130+
131+
Task.create(name="task name", external_id="celery-abc-123")
132+
133+
request = TaskRequest(name="task name", status=StatusEnum.PENDING, external_id="celery-abc-123")
134+
patched_create.assert_called_with(
135+
client=mock.ANY,
136+
organization_slug="org",
137+
project_slug="project",
138+
body=request,
139+
)
140+
141+
142+
def test_update_external_id(settings, patched_update):
143+
api_task = task_for_test()
144+
task = Task(api_task)
145+
146+
patched_update.return_value = Response(HTTPStatus.OK, b"", {}, api_task)
147+
task.update(external_id="celery-abc-123")
148+
149+
_verify_update(settings, patched_update, external_id="celery-abc-123")
150+
151+
127152
def test_before_create_update_task(settings, patched_create):
128153
def before_create(task):
129154
tags = task.setdefault("tags", {})

0 commit comments

Comments
 (0)