vellum-workflow-server 0.14.73.post2__tar.gz → 0.14.73.post5__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 vellum-workflow-server might be problematic. Click here for more details.
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/PKG-INFO +1 -1
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/pyproject.toml +2 -1
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/api/workflow_view.py +3 -5
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/code_exec_runner.py +0 -3
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/core/executor.py +0 -5
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/sentry.py +34 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/system_utils.py +3 -2
- vellum_workflow_server-0.14.73.post5/src/workflow_server/utils/tests/test_sentry_integration.py +69 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/tests/test_system_utils.py +1 -1
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/README.md +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/__init__.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/api/__init__.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/api/auth_middleware.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/api/healthz_view.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/api/tests/__init__.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/api/tests/test_input_display_mapping.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/api/tests/test_workflow_view.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/api/tests/test_workflow_view_stream_workflow_route.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/config.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/core/__init__.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/core/cancel_workflow.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/core/events.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/core/utils.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/core/workflow_executor_context.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/server.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/start.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/__init__.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/exit_handler.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/log_proxy.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/oom_killer.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/tests/__init__.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/tests/test_utils.py +0 -0
- {vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/src/workflow_server/utils/utils.py +0 -0
{vellum_workflow_server-0.14.73.post2 → vellum_workflow_server-0.14.73.post5}/pyproject.toml
RENAMED
|
@@ -3,7 +3,7 @@ name = "vellum-workflow-server"
|
|
|
3
3
|
|
|
4
4
|
[tool.poetry]
|
|
5
5
|
name = "vellum-workflow-server"
|
|
6
|
-
version = "0.14.73.
|
|
6
|
+
version = "0.14.73.post5"
|
|
7
7
|
description = ""
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
authors = []
|
|
@@ -32,6 +32,7 @@ packages = [
|
|
|
32
32
|
|
|
33
33
|
[tool.poetry.group.dev.dependencies]
|
|
34
34
|
requests-mock = "^1.12.1"
|
|
35
|
+
pytest-mock = "^3.14.1"
|
|
35
36
|
|
|
36
37
|
[project.urls]
|
|
37
38
|
Repository = 'https://github.com/vellum-ai/vembda-service'
|
|
@@ -15,7 +15,6 @@ from typing import Any, Dict, Generator, Iterator, Union, cast
|
|
|
15
15
|
|
|
16
16
|
from flask import Blueprint, Response, current_app as app, request, stream_with_context
|
|
17
17
|
from pydantic import ValidationError
|
|
18
|
-
import sentry_sdk
|
|
19
18
|
from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
|
|
20
19
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
|
21
20
|
|
|
@@ -115,7 +114,6 @@ def stream_workflow_route() -> Response:
|
|
|
115
114
|
)
|
|
116
115
|
increment_process_count(1)
|
|
117
116
|
except Exception as e:
|
|
118
|
-
sentry_sdk.set_tag("vellum_trace_id", str(context.trace_id))
|
|
119
117
|
logger.exception(e)
|
|
120
118
|
|
|
121
119
|
process_output_queue.put(create_vembda_rejected_event(context, traceback.format_exc()))
|
|
@@ -202,7 +200,6 @@ def stream_workflow_route() -> Response:
|
|
|
202
200
|
|
|
203
201
|
continue
|
|
204
202
|
except Exception as e:
|
|
205
|
-
sentry_sdk.set_tag("vellum_trace_id", str(context.trace_id))
|
|
206
203
|
logger.exception(e)
|
|
207
204
|
break
|
|
208
205
|
|
|
@@ -237,6 +234,9 @@ def stream_workflow_route() -> Response:
|
|
|
237
234
|
f"process count: {get_active_process_count()}"
|
|
238
235
|
)
|
|
239
236
|
except GeneratorExit:
|
|
237
|
+
# These can happen either from Vembda disconnects (possibily from predict disconnects) or
|
|
238
|
+
# from knative activator gateway timeouts which are caused by idleTimeout or responseStartSeconds
|
|
239
|
+
# being exceeded.
|
|
240
240
|
app.logger.error("Client disconnected in the middle of the Workflow Stream")
|
|
241
241
|
return
|
|
242
242
|
finally:
|
|
@@ -300,7 +300,6 @@ def stream_node_route() -> Response:
|
|
|
300
300
|
# This happens when theres a problem with the stream function call
|
|
301
301
|
# itself not the workflow runner
|
|
302
302
|
yield create_vembda_rejected_event(context, "Internal Server Error")
|
|
303
|
-
sentry_sdk.set_tag("vellum_trace_id", str(context.trace_id))
|
|
304
303
|
app.logger.exception(stream_future.exception())
|
|
305
304
|
break
|
|
306
305
|
else:
|
|
@@ -377,7 +376,6 @@ def get_version_route() -> tuple[dict, int]:
|
|
|
377
376
|
|
|
378
377
|
resp["nodes"] = nodes
|
|
379
378
|
except Exception as e:
|
|
380
|
-
sentry_sdk.set_tag("vellum_trace_id", "unknown")
|
|
381
379
|
logger.exception(f"Failed to discover nodes: {str(e)}")
|
|
382
380
|
resp["nodes"] = []
|
|
383
381
|
|
|
@@ -5,8 +5,6 @@ import os
|
|
|
5
5
|
from uuid import uuid4
|
|
6
6
|
from typing import Optional
|
|
7
7
|
|
|
8
|
-
import sentry_sdk
|
|
9
|
-
|
|
10
8
|
from vellum.workflows.exceptions import WorkflowInitializationException
|
|
11
9
|
from workflow_server.api.workflow_view import get_workflow_request_context
|
|
12
10
|
from workflow_server.core.events import VembdaExecutionInitiatedBody, VembdaExecutionInitiatedEvent
|
|
@@ -56,7 +54,6 @@ def run_code_exec_stream() -> None:
|
|
|
56
54
|
fulfilled_event = serialize_vembda_rejected_event(context, str(e))
|
|
57
55
|
print(f"{_EVENT_LINE}{fulfilled_event}") # noqa: T201
|
|
58
56
|
except Exception as e:
|
|
59
|
-
sentry_sdk.set_tag("vellum_trace_id", str(context.trace_id) if context else "unknown")
|
|
60
57
|
logger.exception(e)
|
|
61
58
|
|
|
62
59
|
event = serialize_vembda_rejected_event(context, "Internal Server Error")
|
|
@@ -15,7 +15,6 @@ from uuid import UUID, uuid4
|
|
|
15
15
|
from typing import Any, Callable, Generator, Iterator, Optional, Tuple, Type
|
|
16
16
|
|
|
17
17
|
from pebble import concurrent
|
|
18
|
-
import sentry_sdk
|
|
19
18
|
from vellum_ee.workflows.display.workflows import BaseWorkflowDisplay
|
|
20
19
|
from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder
|
|
21
20
|
|
|
@@ -68,7 +67,6 @@ def _stream_node_wrapper(executor_context: NodeExecutorContext, queue: Queue) ->
|
|
|
68
67
|
for event in stream_node(executor_context=executor_context):
|
|
69
68
|
queue.put(event)
|
|
70
69
|
except Exception as e:
|
|
71
|
-
sentry_sdk.set_tag("vellum_trace_id", str(executor_context.trace_id))
|
|
72
70
|
logger.exception(e)
|
|
73
71
|
queue.put(
|
|
74
72
|
VembdaExecutionFulfilledEvent(
|
|
@@ -106,7 +104,6 @@ def _stream_workflow_wrapper(executor_context: WorkflowExecutorContext, queue: Q
|
|
|
106
104
|
if not span_id_emitted:
|
|
107
105
|
queue.put(f"{SPAN_ID_EVENT}:{uuid4()}")
|
|
108
106
|
|
|
109
|
-
sentry_sdk.set_tag("vellum_trace_id", str(executor_context.trace_id))
|
|
110
107
|
logger.exception(e)
|
|
111
108
|
queue.put(serialize_vembda_rejected_event(executor_context, "Internal Server Error"))
|
|
112
109
|
queue.put(STREAM_FINISHED_EVENT)
|
|
@@ -456,7 +453,6 @@ def _gather_workflow(context: WorkflowExecutorContext) -> Tuple[BaseWorkflow, st
|
|
|
456
453
|
)
|
|
457
454
|
return workflow, namespace
|
|
458
455
|
except Exception as e:
|
|
459
|
-
sentry_sdk.set_tag("vellum_trace_id", str(context.trace_id))
|
|
460
456
|
logger.exception("Failed to initialize Workflow")
|
|
461
457
|
raise WorkflowInitializationException(f"Failed to initialize workflow: {e}") from e
|
|
462
458
|
|
|
@@ -465,6 +461,5 @@ def _gather_display_context(workflow: BaseWorkflow, namespace: str) -> Optional[
|
|
|
465
461
|
try:
|
|
466
462
|
return BaseWorkflowDisplay.gather_event_display_context(namespace, workflow.__class__)
|
|
467
463
|
except Exception:
|
|
468
|
-
sentry_sdk.set_tag("vellum_trace_id", "unknown")
|
|
469
464
|
logger.exception("Unable to Parse Workflow Display Context")
|
|
470
465
|
return None
|
|
@@ -5,10 +5,44 @@ import sentry_sdk
|
|
|
5
5
|
from sentry_sdk.integrations.logging import LoggingIntegration
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
def _tag_trace_id(event: dict) -> None:
|
|
9
|
+
if "request" not in event:
|
|
10
|
+
return
|
|
11
|
+
|
|
12
|
+
if not isinstance(event["request"], dict):
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
url = event["request"].get("url")
|
|
16
|
+
if not isinstance(url, str):
|
|
17
|
+
return
|
|
18
|
+
|
|
19
|
+
if not url.endswith("/workflow/stream"):
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
body = event["request"].get("data")
|
|
23
|
+
if not isinstance(body, dict):
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
execution_context = body.get("execution_context")
|
|
27
|
+
if not isinstance(execution_context, dict):
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
trace_id = execution_context.get("trace_id")
|
|
31
|
+
if not isinstance(trace_id, str):
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
if "tags" not in event:
|
|
35
|
+
event["tags"] = {}
|
|
36
|
+
|
|
37
|
+
event["tags"]["vellum_trace_id"] = trace_id
|
|
38
|
+
|
|
39
|
+
|
|
8
40
|
def before_send(event: dict, hint: dict) -> Optional[dict]:
|
|
9
41
|
if "exc_info" in hint:
|
|
10
42
|
_, _, _ = hint["exc_info"]
|
|
11
43
|
|
|
44
|
+
_tag_trace_id(event)
|
|
45
|
+
|
|
12
46
|
return event
|
|
13
47
|
|
|
14
48
|
|
|
@@ -12,8 +12,9 @@ WARN_MEMORY_PERCENT = 0.90
|
|
|
12
12
|
FORCE_GC_MEMORY_PERCENT = 0.75
|
|
13
13
|
|
|
14
14
|
_MAX_PROCESS_COUNT = math.ceil(CONCURRENCY * 1.7)
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
# Keep these under the 15s knative response start timeout or it may trigger odd behavior
|
|
16
|
+
_MEMORY_CHECK_INTERVAL_SECONDS = 2
|
|
17
|
+
_MAX_MEMORY_CHECK_ATTEMPTS = 3
|
|
17
18
|
_ACTIVE_PROCESS_COUNT = multiprocessing.Value("i", 0)
|
|
18
19
|
_ACTIVE_PROCESS_LOCK = multiprocessing.Lock()
|
|
19
20
|
|
vellum_workflow_server-0.14.73.post5/src/workflow_server/utils/tests/test_sentry_integration.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from uuid import uuid4
|
|
3
|
+
|
|
4
|
+
from workflow_server.server import create_app
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.fixture
|
|
8
|
+
def mock_sentry_capture_envelope(mocker):
|
|
9
|
+
mock_transport = mocker.patch("sentry_sdk.client.make_transport")
|
|
10
|
+
return mock_transport.return_value.capture_envelope
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_sentry_integration_with_workflow_endpoints(monkeypatch, mock_sentry_capture_envelope):
|
|
14
|
+
# GIVEN sentry is configured
|
|
15
|
+
monkeypatch.setenv("SENTRY_DSN", "https://test-dsn@sentry.io/1234567890")
|
|
16
|
+
|
|
17
|
+
# AND our /workflow/stream endpoint raises an exception
|
|
18
|
+
def mock_get_version():
|
|
19
|
+
raise Exception("Test exception")
|
|
20
|
+
|
|
21
|
+
monkeypatch.setattr("workflow_server.api.workflow_view.get_version", mock_get_version)
|
|
22
|
+
|
|
23
|
+
# AND we have a mock trace_id
|
|
24
|
+
trace_id = str(uuid4())
|
|
25
|
+
|
|
26
|
+
# AND we have a mock request body
|
|
27
|
+
body = {
|
|
28
|
+
"execution_id": uuid4(),
|
|
29
|
+
"inputs": [],
|
|
30
|
+
"environment_api_key": "test",
|
|
31
|
+
"module": "workflow",
|
|
32
|
+
"timeout": 360,
|
|
33
|
+
"files": {
|
|
34
|
+
"__init__.py": "",
|
|
35
|
+
"workflow.py": """\
|
|
36
|
+
from vellum.workflows import BaseWorkflow
|
|
37
|
+
|
|
38
|
+
class Workflow(BaseWorkflow):
|
|
39
|
+
pass
|
|
40
|
+
""",
|
|
41
|
+
},
|
|
42
|
+
"execution_context": {
|
|
43
|
+
"trace_id": trace_id,
|
|
44
|
+
"parent_context": {
|
|
45
|
+
"type": "API_REQUEST",
|
|
46
|
+
"span_id": str(uuid4()),
|
|
47
|
+
"parent": None,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# WHEN we call the /workflow/version endpoint
|
|
53
|
+
flask_app = create_app()
|
|
54
|
+
|
|
55
|
+
with flask_app.test_client() as test_client:
|
|
56
|
+
response = test_client.post("/workflow/stream", json=body)
|
|
57
|
+
|
|
58
|
+
# THEN we get a 500 error
|
|
59
|
+
assert response.status_code == 500
|
|
60
|
+
|
|
61
|
+
# AND sentry captures the error with the correct data
|
|
62
|
+
assert mock_sentry_capture_envelope.call_count == 1
|
|
63
|
+
envelope = mock_sentry_capture_envelope.call_args[0][0]
|
|
64
|
+
event = envelope.get_event()
|
|
65
|
+
assert event["level"] == "error"
|
|
66
|
+
assert "Test exception" in event["exception"]["values"][0]["value"]
|
|
67
|
+
|
|
68
|
+
# AND the trace_id is tagged
|
|
69
|
+
assert event["tags"]["vellum_trace_id"] == trace_id
|
|
@@ -85,7 +85,7 @@ def test_wait_for_available_process_never_available(mock_get_active_process_coun
|
|
|
85
85
|
assert result is False
|
|
86
86
|
|
|
87
87
|
# Should sleep for each attempt
|
|
88
|
-
assert mock_sleep.call_count ==
|
|
88
|
+
assert mock_sleep.call_count == 3
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
@patch("workflow_server.utils.system_utils.time.sleep")
|
|
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
|