langgraph-api 0.2.40__tar.gz → 0.2.42__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.
Potentially problematic release.
This version of langgraph-api might be problematic. Click here for more details.
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/PKG-INFO +1 -1
- langgraph_api-0.2.42/langgraph_api/__init__.py +1 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/api/runs.py +7 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/middleware/request_id.py +2 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/models/run.py +15 -2
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/worker.py +62 -13
- langgraph_api-0.2.40/langgraph_api/__init__.py +0 -1
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/.gitignore +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/LICENSE +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/Makefile +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/README.md +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/benchmark/weather.js +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/constraints.txt +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/forbidden.txt +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/healthcheck.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/api/__init__.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/api/assistants.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/api/mcp.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/api/meta.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/api/store.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/api/ui.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/asgi_transport.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/asyncio.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/auth/custom.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/auth/noop.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/auth/studio_user.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/cli.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/command.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/config.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/cron_scheduler.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/graph.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/http.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/.prettierrc +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/__init__.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/base.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/build.mts +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/client.http.mts +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/client.mts +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/errors.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/package.json +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/remote.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/schema.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/src/load.hooks.mjs +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/src/preload.mjs +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/src/utils/files.mts +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/src/utils/serde.mts +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/sse.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/tsconfig.json +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/ui.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/js/yarn.lock +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/logging.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/metadata.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/middleware/__init__.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/middleware/http_logger.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/middleware/private_network.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/patch.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/queue_entrypoint.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/route.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/schema.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/serde.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/server.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/sse.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/state.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/store.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/stream.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/thread_ttl.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/tunneling/cloudflare.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/utils.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/validation.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_api/webhook.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/langgraph_runtime/__init__.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/logging.json +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/openapi.json +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/pyproject.toml +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/scripts/create_license.py +0 -0
- {langgraph_api-0.2.40 → langgraph_api-0.2.42}/uv.lock +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.42"
|
|
@@ -38,6 +38,7 @@ async def create_run(request: ApiRequest):
|
|
|
38
38
|
thread_id,
|
|
39
39
|
payload,
|
|
40
40
|
request.headers,
|
|
41
|
+
request_start_time=request.scope.get("request_start_time_ms"),
|
|
41
42
|
)
|
|
42
43
|
return ApiResponse(
|
|
43
44
|
run,
|
|
@@ -55,6 +56,7 @@ async def create_stateless_run(request: ApiRequest):
|
|
|
55
56
|
None,
|
|
56
57
|
payload,
|
|
57
58
|
request.headers,
|
|
59
|
+
request_start_time=request.scope.get("request_start_time_ms"),
|
|
58
60
|
)
|
|
59
61
|
return ApiResponse(
|
|
60
62
|
run,
|
|
@@ -75,6 +77,7 @@ async def create_stateless_run_batch(request: ApiRequest):
|
|
|
75
77
|
payload,
|
|
76
78
|
request.headers,
|
|
77
79
|
barrier,
|
|
80
|
+
request_start_time=request.scope.get("request_start_time_ms"),
|
|
78
81
|
)
|
|
79
82
|
for payload in batch_payload
|
|
80
83
|
]
|
|
@@ -100,6 +103,7 @@ async def stream_run(
|
|
|
100
103
|
payload,
|
|
101
104
|
request.headers,
|
|
102
105
|
run_id=run_id,
|
|
106
|
+
request_start_time=request.scope.get("request_start_time_ms"),
|
|
103
107
|
)
|
|
104
108
|
except Exception:
|
|
105
109
|
if not sub.cancelled():
|
|
@@ -139,6 +143,7 @@ async def stream_run_stateless(
|
|
|
139
143
|
payload,
|
|
140
144
|
request.headers,
|
|
141
145
|
run_id=run_id,
|
|
146
|
+
request_start_time=request.scope.get("request_start_time_ms"),
|
|
142
147
|
)
|
|
143
148
|
except Exception:
|
|
144
149
|
if not sub.cancelled():
|
|
@@ -178,6 +183,7 @@ async def wait_run(request: ApiRequest):
|
|
|
178
183
|
payload,
|
|
179
184
|
request.headers,
|
|
180
185
|
run_id=run_id,
|
|
186
|
+
request_start_time=request.scope.get("request_start_time_ms"),
|
|
181
187
|
)
|
|
182
188
|
except Exception:
|
|
183
189
|
if not sub.cancelled():
|
|
@@ -250,6 +256,7 @@ async def wait_run_stateless(request: ApiRequest):
|
|
|
250
256
|
payload,
|
|
251
257
|
request.headers,
|
|
252
258
|
run_id=run_id,
|
|
259
|
+
request_start_time=request.scope.get("request_start_time_ms"),
|
|
253
260
|
)
|
|
254
261
|
except Exception:
|
|
255
262
|
if not sub.cancelled():
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Middleware to handle setting request IDs for logging."""
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
+
import time
|
|
4
5
|
import uuid
|
|
5
6
|
|
|
6
7
|
from starlette.types import ASGIApp, Receive, Scope, Send
|
|
@@ -27,4 +28,5 @@ class RequestIdMiddleware:
|
|
|
27
28
|
if request_id is None:
|
|
28
29
|
request_id = str(uuid.uuid4()).encode()
|
|
29
30
|
scope["headers"].append((b"x-request-id", request_id))
|
|
31
|
+
scope["request_start_time_ms"] = int(time.time() * 1000)
|
|
30
32
|
await self.app(scope, receive, send)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import functools
|
|
3
3
|
import re
|
|
4
|
+
import time
|
|
4
5
|
import urllib.parse
|
|
5
6
|
import uuid
|
|
6
7
|
from collections.abc import Mapping, Sequence
|
|
@@ -249,6 +250,7 @@ async def create_valid_run(
|
|
|
249
250
|
headers: Mapping[str, str],
|
|
250
251
|
barrier: asyncio.Barrier | None = None,
|
|
251
252
|
run_id: UUID | None = None,
|
|
253
|
+
request_start_time: float | None = None,
|
|
252
254
|
) -> Run:
|
|
253
255
|
request_id = headers.get("x-request-id") # Will be null in the crons scheduler.
|
|
254
256
|
(
|
|
@@ -293,6 +295,11 @@ async def create_valid_run(
|
|
|
293
295
|
user_id = None
|
|
294
296
|
if not configurable.get("langgraph_request_id"):
|
|
295
297
|
configurable["langgraph_request_id"] = request_id
|
|
298
|
+
if request_start_time:
|
|
299
|
+
configurable["__request_start_time_ms__"] = request_start_time
|
|
300
|
+
after_seconds = payload.get("after_seconds", 0)
|
|
301
|
+
configurable["__after_seconds__"] = after_seconds
|
|
302
|
+
put_time_start = time.time()
|
|
296
303
|
run_coro = Runs.put(
|
|
297
304
|
conn,
|
|
298
305
|
assistant_id,
|
|
@@ -317,7 +324,7 @@ async def create_valid_run(
|
|
|
317
324
|
run_id=run_id,
|
|
318
325
|
multitask_strategy=multitask_strategy,
|
|
319
326
|
prevent_insert_if_inflight=prevent_insert_if_inflight,
|
|
320
|
-
after_seconds=
|
|
327
|
+
after_seconds=after_seconds,
|
|
321
328
|
if_not_exists=payload.get("if_not_exists", "reject"),
|
|
322
329
|
)
|
|
323
330
|
run_ = await run_coro
|
|
@@ -344,8 +351,14 @@ async def create_valid_run(
|
|
|
344
351
|
multitask_strategy=multitask_strategy,
|
|
345
352
|
stream_mode=stream_mode,
|
|
346
353
|
temporary=temporary,
|
|
347
|
-
after_seconds=
|
|
354
|
+
after_seconds=after_seconds,
|
|
348
355
|
if_not_exists=payload.get("if_not_exists", "reject"),
|
|
356
|
+
run_create_ms=(
|
|
357
|
+
int(time.time() * 1_000) - request_start_time
|
|
358
|
+
if request_start_time
|
|
359
|
+
else None
|
|
360
|
+
),
|
|
361
|
+
run_put_ms=int((time.time() - put_time_start) * 1_000),
|
|
349
362
|
)
|
|
350
363
|
# inserted, proceed
|
|
351
364
|
if multitask_strategy in ("interrupt", "rollback") and inflight_runs:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import time
|
|
2
3
|
from collections.abc import AsyncGenerator
|
|
3
4
|
from contextlib import AsyncExitStack, asynccontextmanager
|
|
4
5
|
from datetime import UTC, datetime
|
|
@@ -74,8 +75,21 @@ async def worker(
|
|
|
74
75
|
exception: Exception | None = None
|
|
75
76
|
status: str | None = None
|
|
76
77
|
webhook = run["kwargs"].get("webhook", None)
|
|
77
|
-
|
|
78
|
+
request_created_at: int | None = run["kwargs"]["config"]["configurable"].get(
|
|
79
|
+
"__request_start_time_ms__"
|
|
80
|
+
)
|
|
81
|
+
after_seconds = run["kwargs"]["config"]["configurable"].get("__after_seconds__", 0)
|
|
78
82
|
run_ended_at: str | None = None
|
|
83
|
+
run_started_at = datetime.now(UTC)
|
|
84
|
+
# Note that "created_at" is inclusive of the `after_seconds`
|
|
85
|
+
run_creation_ms = (
|
|
86
|
+
int(
|
|
87
|
+
((run["created_at"].timestamp() - after_seconds) * 1_000)
|
|
88
|
+
- request_created_at
|
|
89
|
+
)
|
|
90
|
+
if request_created_at is not None
|
|
91
|
+
else None
|
|
92
|
+
)
|
|
79
93
|
|
|
80
94
|
async with (
|
|
81
95
|
connect() as conn,
|
|
@@ -95,11 +109,13 @@ async def worker(
|
|
|
95
109
|
"request_id": _get_request_id(run),
|
|
96
110
|
}
|
|
97
111
|
)
|
|
98
|
-
|
|
112
|
+
run_stream_started_at = datetime.now(UTC)
|
|
99
113
|
await logger.ainfo(
|
|
100
114
|
"Starting background run",
|
|
101
115
|
run_started_at=run_started_at.isoformat(),
|
|
116
|
+
run_creation_ms=run_creation_ms,
|
|
102
117
|
run_queue_ms=ms(run_started_at, run["created_at"]),
|
|
118
|
+
run_stream_start_ms=ms(run_stream_started_at, run_started_at),
|
|
103
119
|
)
|
|
104
120
|
|
|
105
121
|
def on_checkpoint(checkpoint_arg: CheckpointPayload):
|
|
@@ -115,7 +131,15 @@ async def worker(
|
|
|
115
131
|
|
|
116
132
|
try:
|
|
117
133
|
if attempt > BG_JOB_MAX_RETRIES:
|
|
118
|
-
await logger.aerror(
|
|
134
|
+
await logger.aerror(
|
|
135
|
+
"Run exceeded max attempts",
|
|
136
|
+
run_id=run["run_id"],
|
|
137
|
+
run_completed_in_ms=(
|
|
138
|
+
int((time.time() * 1_000) - request_created_at)
|
|
139
|
+
if request_created_at is not None
|
|
140
|
+
else None
|
|
141
|
+
),
|
|
142
|
+
)
|
|
119
143
|
|
|
120
144
|
error_message = (
|
|
121
145
|
f"Run {run['run_id']} exceeded max attempts ({BG_JOB_MAX_RETRIES}).\n\n"
|
|
@@ -149,7 +173,8 @@ async def worker(
|
|
|
149
173
|
consume(stream, run_id, resumable),
|
|
150
174
|
BG_JOB_TIMEOUT_SECS,
|
|
151
175
|
)
|
|
152
|
-
|
|
176
|
+
run_ended_at_dt = datetime.now(UTC)
|
|
177
|
+
run_ended_at = run_ended_at_dt.isoformat()
|
|
153
178
|
await logger.ainfo(
|
|
154
179
|
"Background run succeeded",
|
|
155
180
|
run_id=str(run_id),
|
|
@@ -157,7 +182,12 @@ async def worker(
|
|
|
157
182
|
run_created_at=run_created_at,
|
|
158
183
|
run_started_at=run_started_at.isoformat(),
|
|
159
184
|
run_ended_at=run_ended_at,
|
|
160
|
-
run_exec_ms=ms(
|
|
185
|
+
run_exec_ms=ms(run_ended_at_dt, run_started_at),
|
|
186
|
+
run_completed_in_ms=(
|
|
187
|
+
int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
|
|
188
|
+
if request_created_at is not None
|
|
189
|
+
else None
|
|
190
|
+
),
|
|
161
191
|
)
|
|
162
192
|
status = "success"
|
|
163
193
|
await Runs.set_status(conn, run_id, "success")
|
|
@@ -173,12 +203,18 @@ async def worker(
|
|
|
173
203
|
run_started_at=run_started_at.isoformat(),
|
|
174
204
|
run_ended_at=run_ended_at,
|
|
175
205
|
run_exec_ms=ms(datetime.now(UTC), run_started_at),
|
|
206
|
+
run_completed_in_ms=(
|
|
207
|
+
int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
|
|
208
|
+
if request_created_at is not None
|
|
209
|
+
else None
|
|
210
|
+
),
|
|
176
211
|
)
|
|
177
212
|
await Runs.set_status(conn, run_id, "timeout")
|
|
178
213
|
except UserRollback as e:
|
|
179
214
|
exception = e
|
|
180
215
|
status = "rollback"
|
|
181
|
-
|
|
216
|
+
run_ended_at_dt = datetime.now(UTC)
|
|
217
|
+
run_ended_at = run_ended_at_dt.isoformat()
|
|
182
218
|
try:
|
|
183
219
|
await Runs.delete(conn, run_id, thread_id=run["thread_id"])
|
|
184
220
|
await logger.ainfo(
|
|
@@ -188,7 +224,12 @@ async def worker(
|
|
|
188
224
|
run_created_at=run_created_at,
|
|
189
225
|
run_started_at=run_started_at.isoformat(),
|
|
190
226
|
run_ended_at=run_ended_at,
|
|
191
|
-
run_exec_ms=ms(
|
|
227
|
+
run_exec_ms=ms(run_ended_at_dt, run_started_at),
|
|
228
|
+
run_completed_in_ms=(
|
|
229
|
+
int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
|
|
230
|
+
if request_created_at is not None
|
|
231
|
+
else None
|
|
232
|
+
),
|
|
192
233
|
)
|
|
193
234
|
|
|
194
235
|
except InFailedSqlTransaction as e:
|
|
@@ -217,7 +258,8 @@ async def worker(
|
|
|
217
258
|
except UserInterrupt as e:
|
|
218
259
|
exception = e
|
|
219
260
|
status = "interrupted"
|
|
220
|
-
|
|
261
|
+
run_ended_at_dt = datetime.now(UTC)
|
|
262
|
+
run_ended_at = run_ended_at_dt.isoformat()
|
|
221
263
|
await logger.ainfo(
|
|
222
264
|
"Background run interrupted",
|
|
223
265
|
run_id=str(run_id),
|
|
@@ -225,13 +267,19 @@ async def worker(
|
|
|
225
267
|
run_created_at=run_created_at,
|
|
226
268
|
run_started_at=run_started_at.isoformat(),
|
|
227
269
|
run_ended_at=run_ended_at,
|
|
228
|
-
run_exec_ms=ms(
|
|
270
|
+
run_exec_ms=ms(run_ended_at_dt, run_started_at),
|
|
271
|
+
run_completed_in_ms=(
|
|
272
|
+
int((run_ended_at_dt.timestamp() * 1_000) - request_created_at)
|
|
273
|
+
if request_created_at is not None
|
|
274
|
+
else None
|
|
275
|
+
),
|
|
229
276
|
)
|
|
230
277
|
await Runs.set_status(conn, run_id, "interrupted")
|
|
231
278
|
except RETRIABLE_EXCEPTIONS as e:
|
|
232
279
|
exception = e
|
|
233
280
|
status = "retry"
|
|
234
|
-
|
|
281
|
+
run_ended_at_dt = datetime.now(UTC)
|
|
282
|
+
run_ended_at = run_ended_at_dt.isoformat()
|
|
235
283
|
await logger.awarning(
|
|
236
284
|
f"Background run failed, will retry. Exception: {e}",
|
|
237
285
|
exc_info=True,
|
|
@@ -240,14 +288,15 @@ async def worker(
|
|
|
240
288
|
run_created_at=run_created_at,
|
|
241
289
|
run_started_at=run_started_at.isoformat(),
|
|
242
290
|
run_ended_at=run_ended_at,
|
|
243
|
-
run_exec_ms=ms(
|
|
291
|
+
run_exec_ms=ms(run_ended_at_dt, run_started_at),
|
|
244
292
|
)
|
|
245
293
|
await Runs.set_status(conn, run_id, "pending")
|
|
246
294
|
raise
|
|
247
295
|
except Exception as exc:
|
|
248
296
|
exception = exc
|
|
249
297
|
status = "error"
|
|
250
|
-
|
|
298
|
+
run_ended_at_dt = datetime.now(UTC)
|
|
299
|
+
run_ended_at = run_ended_at_dt.isoformat()
|
|
251
300
|
await logger.aexception(
|
|
252
301
|
f"Background run failed. Exception: {exc}",
|
|
253
302
|
exc_info=not isinstance(exc, RemoteException),
|
|
@@ -256,7 +305,7 @@ async def worker(
|
|
|
256
305
|
run_created_at=run_created_at,
|
|
257
306
|
run_started_at=run_started_at.isoformat(),
|
|
258
307
|
run_ended_at=run_ended_at,
|
|
259
|
-
run_exec_ms=ms(
|
|
308
|
+
run_exec_ms=ms(run_ended_at_dt, run_started_at),
|
|
260
309
|
)
|
|
261
310
|
await Runs.set_status(conn, run_id, "error")
|
|
262
311
|
set_auth_ctx(None, None)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.40"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|