edda-framework 0.9.1__tar.gz → 0.10.0__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.
- {edda_framework-0.9.1 → edda_framework-0.10.0}/Justfile +19 -2
- {edda_framework-0.9.1 → edda_framework-0.10.0}/PKG-INFO +13 -1
- {edda_framework-0.9.1 → edda_framework-0.10.0}/README.md +8 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/demo_app.py +24 -6
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/api/reference.md +8 -0
- edda_framework-0.10.0/docs/core-features/events/postgres-notify.md +166 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/getting-started/installation.md +45 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/index.md +1 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/setup.md +13 -1
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/app.py +419 -26
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/outbox/relayer.py +21 -2
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/storage/__init__.py +8 -0
- edda_framework-0.10.0/edda/storage/notify_base.py +162 -0
- edda_framework-0.10.0/edda/storage/pg_notify.py +325 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/storage/protocol.py +9 -1
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/storage/sqlalchemy_storage.py +193 -13
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/viewer_ui/app.py +26 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/viewer_ui/data_service.py +4 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/pyproject.toml +11 -1
- edda_framework-0.10.0/tests/test_pg_notify.py +298 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_storage.py +156 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/uv.lock +36 -2
- {edda_framework-0.9.1 → edda_framework-0.10.0}/.github/workflows/ci.yml +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/.github/workflows/docs.yml +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/.github/workflows/release.yml +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/.gitignore +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/.python-version +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/LICENSE +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/core-features/durable-execution/replay.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/core-features/events/cloudevents-http-binding.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/core-features/events/wait-event.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/core-features/hooks.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/core-features/messages.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/core-features/retry.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/core-features/saga-compensation.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/core-features/transactional-outbox.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/core-features/workflows-activities.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/examples/ecommerce.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/examples/events.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/examples/fastapi-integration.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/examples/saga.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/examples/simple.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/getting-started/concepts.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/getting-started/first-workflow.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/getting-started/quick-start.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/integrations/mcp.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/integrations/opentelemetry.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/integrations/pydantic-rpc.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/images/cloudevents-cli-trigger.png +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/images/compensation-execution.png +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/images/detail-page-loan-approval.png +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/images/detail-page-match-case.png +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/images/nested-pydantic-form.png +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/images/start-workflow-form-pydantic.png +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/images/wait-event-visualization.png +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/images/workflow-list-view.png +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/images/workflow-selection-dropdown.png +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/docs/viewer-ui/visualization.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/activity.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/channels.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/compensation.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/context.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/exceptions.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/hooks.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/integrations/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/integrations/mcp/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/integrations/mcp/decorators.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/integrations/mcp/server.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/integrations/opentelemetry/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/integrations/opentelemetry/hooks.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/locking.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/outbox/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/outbox/transactional.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/pydantic_utils.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/replay.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/retry.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/serialization/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/serialization/base.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/serialization/json.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/storage/models.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/viewer_ui/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/viewer_ui/components.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/viewer_ui/theme.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/visualizer/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/visualizer/ast_analyzer.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/visualizer/mermaid_generator.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/workflow.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/edda/wsgi.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/cancellable_workflow.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/compensation_workflow.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/event_waiting_app.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/event_waiting_workflow.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/event_waiting_workflow_complete.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/long_running_loop.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/mcp/README.md +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/mcp/order_processing_mcp.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/mcp/prompts_example.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/mcp/remote_server_example.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/mcp/simple_mcp_server.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/message_passing.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/observability_with_logfire.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/observability_with_opentelemetry.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/pydantic_rpc_integration.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/pydantic_saga.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/retry_example.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/retry_with_compensation.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/simple_workflow.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/typeddict_example.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/examples/with_outbox.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/conftest.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/integrations/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/integrations/mcp/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/integrations/mcp/test_cancel.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/integrations/mcp/test_integration.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/integrations/mcp/test_jsonrpc.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/integrations/mcp/test_prompts.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/integrations/mcp/test_server.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/integrations/opentelemetry/__init__.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/integrations/opentelemetry/test_hooks.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_activity.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_activity_retry.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_activity_sync.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_app.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_ast_analyzer.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_atomic_wait_event.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_auto_migration.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_binary_data.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_channel_competing.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_channel_transactional.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_cloudevents_http_binding.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_compensation.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_compensation_crash_recovery.py.wip +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_concurrent_outbox.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_context.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_ctx_session.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_distributed_event_delivery.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_events.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_instance_id_routing.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_lock_race_condition.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_lock_timeout_customization.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_locking.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_message_cleanup.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_message_delivery_lock.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_messages.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_multidb_storage.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_outbox.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_pydantic_activity.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_pydantic_enum.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_pydantic_events.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_pydantic_saga.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_pydantic_utils.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_receive_timeout.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_received_event.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_recur.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_recur_cleanup.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_replay.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_retry_policy.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_saga_parameter_extraction.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_serialization.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_skip_locked.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_stale_workflow_recovery.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_storage_mysql.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_storage_postgresql.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_transactions.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_viewer_pagination.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_viewer_pydantic_form.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_viewer_start_saga.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_wait_timer.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_workflow.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_workflow_auto_register.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_workflow_cancellation.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/tests/test_workflow_resumption.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/viewer_app.py +0 -0
- {edda_framework-0.9.1 → edda_framework-0.10.0}/zensical.toml +0 -0
|
@@ -11,7 +11,7 @@ install:
|
|
|
11
11
|
|
|
12
12
|
# Install all dependencies including database drivers
|
|
13
13
|
install-all:
|
|
14
|
-
uv sync --extra dev --extra postgresql --extra mysql
|
|
14
|
+
uv sync --extra dev --extra postgresql --extra mysql --extra postgres-notify
|
|
15
15
|
|
|
16
16
|
# Install viewer dependencies
|
|
17
17
|
install-viewer:
|
|
@@ -71,15 +71,32 @@ demo:
|
|
|
71
71
|
# Run demo application with PostgreSQL (requires local PostgreSQL)
|
|
72
72
|
# Usage: just demo-postgresql
|
|
73
73
|
# Requires: EDDA_POSTGRES_PASSWORD environment variable
|
|
74
|
+
# Uses LISTEN/NOTIFY for instant notifications (auto-detected)
|
|
74
75
|
demo-postgresql:
|
|
76
|
+
@echo "Stopping existing demo app on port 8001..."
|
|
77
|
+
@lsof -ti :8001 | xargs kill -15 2>/dev/null || true
|
|
78
|
+
@sleep 1
|
|
79
|
+
@lsof -ti :8001 | xargs kill -9 2>/dev/null || true
|
|
80
|
+
@echo "Ensuring server and PostgreSQL dependencies are installed..."
|
|
81
|
+
@uv sync --extra server --extra postgresql --extra postgres-notify --quiet
|
|
82
|
+
@echo "Starting demo app with PostgreSQL (NOTIFY enabled)..."
|
|
83
|
+
EDDA_DB_URL="postgresql+asyncpg://postgres:{{env_var('EDDA_POSTGRES_PASSWORD')}}@localhost:5432/edda" \
|
|
84
|
+
uv run tsuno demo_app:application --bind 127.0.0.1:8001
|
|
85
|
+
|
|
86
|
+
# Run demo application with PostgreSQL but WITHOUT NOTIFY (polling only)
|
|
87
|
+
# Usage: just demo-postgresql-polling
|
|
88
|
+
# Requires: EDDA_POSTGRES_PASSWORD environment variable
|
|
89
|
+
# Uses polling-only mode (no LISTEN/NOTIFY) for comparison testing
|
|
90
|
+
demo-postgresql-polling:
|
|
75
91
|
@echo "Stopping existing demo app on port 8001..."
|
|
76
92
|
@lsof -ti :8001 | xargs kill -15 2>/dev/null || true
|
|
77
93
|
@sleep 1
|
|
78
94
|
@lsof -ti :8001 | xargs kill -9 2>/dev/null || true
|
|
79
95
|
@echo "Ensuring server and PostgreSQL dependencies are installed..."
|
|
80
96
|
@uv sync --extra server --extra postgresql --quiet
|
|
81
|
-
@echo "Starting demo app with PostgreSQL..."
|
|
97
|
+
@echo "Starting demo app with PostgreSQL (polling only, NOTIFY disabled)..."
|
|
82
98
|
EDDA_DB_URL="postgresql+asyncpg://postgres:{{env_var('EDDA_POSTGRES_PASSWORD')}}@localhost:5432/edda" \
|
|
99
|
+
EDDA_USE_NOTIFY=false \
|
|
83
100
|
uv run tsuno demo_app:application --bind 127.0.0.1:8001
|
|
84
101
|
|
|
85
102
|
# Run viewer with demo_app using PostgreSQL (requires local PostgreSQL)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: edda-framework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Lightweight Durable Execution Framework
|
|
5
5
|
Project-URL: Homepage, https://github.com/i2y/edda
|
|
6
6
|
Project-URL: Documentation, https://github.com/i2y/edda#readme
|
|
@@ -28,6 +28,8 @@ Requires-Dist: httpx>=0.28.1
|
|
|
28
28
|
Requires-Dist: pydantic>=2.0.0
|
|
29
29
|
Requires-Dist: sqlalchemy[asyncio]>=2.0.0
|
|
30
30
|
Requires-Dist: uvloop>=0.22.1
|
|
31
|
+
Provides-Extra: cpu-monitor
|
|
32
|
+
Requires-Dist: psutil>=5.9.0; extra == 'cpu-monitor'
|
|
31
33
|
Provides-Extra: dev
|
|
32
34
|
Requires-Dist: black>=25.9.0; extra == 'dev'
|
|
33
35
|
Requires-Dist: mcp>=1.22.0; extra == 'dev'
|
|
@@ -48,6 +50,8 @@ Provides-Extra: opentelemetry
|
|
|
48
50
|
Requires-Dist: opentelemetry-api>=1.20.0; extra == 'opentelemetry'
|
|
49
51
|
Requires-Dist: opentelemetry-exporter-otlp>=1.20.0; extra == 'opentelemetry'
|
|
50
52
|
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == 'opentelemetry'
|
|
53
|
+
Provides-Extra: postgres-notify
|
|
54
|
+
Requires-Dist: asyncpg>=0.30.0; extra == 'postgres-notify'
|
|
51
55
|
Provides-Extra: postgresql
|
|
52
56
|
Requires-Dist: asyncpg>=0.30.0; extra == 'postgresql'
|
|
53
57
|
Provides-Extra: server
|
|
@@ -87,6 +91,7 @@ For detailed documentation, visit [https://i2y.github.io/edda/](https://i2y.gith
|
|
|
87
91
|
- ☁️ **CloudEvents Support**: Native support for CloudEvents protocol
|
|
88
92
|
- ⏱️ **Event & Timer Waiting**: Free up worker resources while waiting for events or timers, resume on any available worker
|
|
89
93
|
- 📬 **Channel-based Messaging**: Actor-model style communication with competing (job queue) and broadcast (fan-out) modes
|
|
94
|
+
- ⚡ **Instant Notifications**: PostgreSQL LISTEN/NOTIFY for near-instant event delivery (optional)
|
|
90
95
|
- 🤖 **MCP Integration**: Expose durable workflows as AI tools via Model Context Protocol
|
|
91
96
|
- 🌍 **ASGI/WSGI Support**: Deploy with your preferred server (uvicorn, gunicorn, uWSGI)
|
|
92
97
|
|
|
@@ -221,6 +226,9 @@ uv add edda-framework --extra mysql
|
|
|
221
226
|
# With Viewer UI
|
|
222
227
|
uv add edda-framework --extra viewer
|
|
223
228
|
|
|
229
|
+
# With PostgreSQL instant notifications (LISTEN/NOTIFY)
|
|
230
|
+
uv add edda-framework --extra postgres-notify
|
|
231
|
+
|
|
224
232
|
# All extras (PostgreSQL, MySQL, Viewer UI)
|
|
225
233
|
uv add edda-framework --extra postgresql --extra mysql --extra viewer
|
|
226
234
|
```
|
|
@@ -272,6 +280,8 @@ pip install "git+https://github.com/i2y/edda.git[postgresql,viewer]"
|
|
|
272
280
|
|
|
273
281
|
**Important**: For multi-process or multi-pod deployments (K8s, Docker Compose with multiple replicas, etc.), you **must** use PostgreSQL or MySQL. SQLite supports multiple async workers within a single process, but its table-level locking makes it unsuitable for multi-process/multi-pod scenarios.
|
|
274
282
|
|
|
283
|
+
> **Tip**: For PostgreSQL, install the `postgres-notify` extra for near-instant event delivery using LISTEN/NOTIFY instead of polling.
|
|
284
|
+
|
|
275
285
|
### Development Installation
|
|
276
286
|
|
|
277
287
|
If you want to contribute to Edda or modify the framework itself:
|
|
@@ -492,6 +502,8 @@ app = EddaApp(
|
|
|
492
502
|
# Connection pool settings (optional)
|
|
493
503
|
pool_size=5, # Concurrent connections
|
|
494
504
|
max_overflow=10, # Additional burst capacity
|
|
505
|
+
# Batch processing (optional)
|
|
506
|
+
max_workflows_per_batch=10, # Or "auto" / "auto:cpu" for dynamic scaling
|
|
495
507
|
)
|
|
496
508
|
```
|
|
497
509
|
|
|
@@ -29,6 +29,7 @@ For detailed documentation, visit [https://i2y.github.io/edda/](https://i2y.gith
|
|
|
29
29
|
- ☁️ **CloudEvents Support**: Native support for CloudEvents protocol
|
|
30
30
|
- ⏱️ **Event & Timer Waiting**: Free up worker resources while waiting for events or timers, resume on any available worker
|
|
31
31
|
- 📬 **Channel-based Messaging**: Actor-model style communication with competing (job queue) and broadcast (fan-out) modes
|
|
32
|
+
- ⚡ **Instant Notifications**: PostgreSQL LISTEN/NOTIFY for near-instant event delivery (optional)
|
|
32
33
|
- 🤖 **MCP Integration**: Expose durable workflows as AI tools via Model Context Protocol
|
|
33
34
|
- 🌍 **ASGI/WSGI Support**: Deploy with your preferred server (uvicorn, gunicorn, uWSGI)
|
|
34
35
|
|
|
@@ -163,6 +164,9 @@ uv add edda-framework --extra mysql
|
|
|
163
164
|
# With Viewer UI
|
|
164
165
|
uv add edda-framework --extra viewer
|
|
165
166
|
|
|
167
|
+
# With PostgreSQL instant notifications (LISTEN/NOTIFY)
|
|
168
|
+
uv add edda-framework --extra postgres-notify
|
|
169
|
+
|
|
166
170
|
# All extras (PostgreSQL, MySQL, Viewer UI)
|
|
167
171
|
uv add edda-framework --extra postgresql --extra mysql --extra viewer
|
|
168
172
|
```
|
|
@@ -214,6 +218,8 @@ pip install "git+https://github.com/i2y/edda.git[postgresql,viewer]"
|
|
|
214
218
|
|
|
215
219
|
**Important**: For multi-process or multi-pod deployments (K8s, Docker Compose with multiple replicas, etc.), you **must** use PostgreSQL or MySQL. SQLite supports multiple async workers within a single process, but its table-level locking makes it unsuitable for multi-process/multi-pod scenarios.
|
|
216
220
|
|
|
221
|
+
> **Tip**: For PostgreSQL, install the `postgres-notify` extra for near-instant event delivery using LISTEN/NOTIFY instead of polling.
|
|
222
|
+
|
|
217
223
|
### Development Installation
|
|
218
224
|
|
|
219
225
|
If you want to contribute to Edda or modify the framework itself:
|
|
@@ -434,6 +440,8 @@ app = EddaApp(
|
|
|
434
440
|
# Connection pool settings (optional)
|
|
435
441
|
pool_size=5, # Concurrent connections
|
|
436
442
|
max_overflow=10, # Additional burst capacity
|
|
443
|
+
# Batch processing (optional)
|
|
444
|
+
max_workflows_per_batch=10, # Or "auto" / "auto:cpu" for dynamic scaling
|
|
437
445
|
)
|
|
438
446
|
```
|
|
439
447
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Demo Edda ASGI application for tsuno."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import logging
|
|
4
5
|
import os
|
|
5
6
|
import sys
|
|
6
7
|
from datetime import datetime
|
|
@@ -8,9 +9,17 @@ from enum import Enum
|
|
|
8
9
|
from typing import Any, cast
|
|
9
10
|
|
|
10
11
|
import uvloop
|
|
11
|
-
from pydantic import BaseModel, Field, field_validator
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
# Configure logging to see Edda startup messages (must be before edda import)
|
|
14
|
+
logging.basicConfig(
|
|
15
|
+
level=logging.INFO,
|
|
16
|
+
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
|
|
17
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, Field, field_validator # noqa: E402
|
|
21
|
+
|
|
22
|
+
from edda import ( # noqa: E402
|
|
14
23
|
EddaApp,
|
|
15
24
|
RetryPolicy,
|
|
16
25
|
WorkflowContext,
|
|
@@ -24,7 +33,7 @@ from edda import (
|
|
|
24
33
|
wait_until,
|
|
25
34
|
workflow,
|
|
26
35
|
)
|
|
27
|
-
from edda.wsgi import create_wsgi_app
|
|
36
|
+
from edda.wsgi import create_wsgi_app # noqa: E402
|
|
28
37
|
|
|
29
38
|
# Python 3.12+ uses asyncio.set_event_loop_policy() instead of uvloop.install()
|
|
30
39
|
if sys.version_info >= (3, 12):
|
|
@@ -408,9 +417,18 @@ class ScheduledShipmentResult(BaseModel):
|
|
|
408
417
|
|
|
409
418
|
# Create Edda application
|
|
410
419
|
# Use environment variable EDDA_DB_URL if available, otherwise default to sqlite:///demo.db
|
|
420
|
+
# Use EDDA_USE_NOTIFY to control LISTEN/NOTIFY (true/false/auto, default: auto)
|
|
421
|
+
_use_notify_env = os.getenv("EDDA_USE_NOTIFY", "auto").lower()
|
|
422
|
+
_use_listen_notify: bool | None = None # Auto-detect
|
|
423
|
+
if _use_notify_env == "true":
|
|
424
|
+
_use_listen_notify = True
|
|
425
|
+
elif _use_notify_env == "false":
|
|
426
|
+
_use_listen_notify = False
|
|
427
|
+
|
|
411
428
|
app = EddaApp(
|
|
412
429
|
service_name="demo-service",
|
|
413
430
|
db_url=os.getenv("EDDA_DB_URL", "sqlite:///demo.db"),
|
|
431
|
+
use_listen_notify=_use_listen_notify,
|
|
414
432
|
)
|
|
415
433
|
|
|
416
434
|
|
|
@@ -2115,7 +2133,7 @@ async def job_publisher_workflow(
|
|
|
2115
2133
|
"""
|
|
2116
2134
|
print(f"\n[PUBLISHER] Publishing job: {input.task}")
|
|
2117
2135
|
await publish(ctx, "jobs", {"task": input.task})
|
|
2118
|
-
print(
|
|
2136
|
+
print("[PUBLISHER] Job published to 'jobs' channel")
|
|
2119
2137
|
return {"published": True, "channel": "jobs", "task": input.task}
|
|
2120
2138
|
|
|
2121
2139
|
|
|
@@ -2135,7 +2153,7 @@ async def notification_publisher_workflow(
|
|
|
2135
2153
|
"""
|
|
2136
2154
|
print(f"\n[PUBLISHER] Publishing notification: {input.message}")
|
|
2137
2155
|
await publish(ctx, "notifications", {"message": input.message})
|
|
2138
|
-
print(
|
|
2156
|
+
print("[PUBLISHER] Notification published to 'notifications' channel")
|
|
2139
2157
|
return {"published": True, "channel": "notifications", "message": input.message}
|
|
2140
2158
|
|
|
2141
2159
|
|
|
@@ -2194,7 +2212,7 @@ async def direct_message_sender_workflow(
|
|
|
2194
2212
|
|
|
2195
2213
|
await send_to(ctx, input.target_instance_id, {"message": input.message})
|
|
2196
2214
|
|
|
2197
|
-
print(
|
|
2215
|
+
print("[SENDER] Message sent!")
|
|
2198
2216
|
return DirectMessageSenderResult(
|
|
2199
2217
|
sent=True,
|
|
2200
2218
|
target_instance_id=input.target_instance_id,
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# PostgreSQL LISTEN/NOTIFY
|
|
2
|
+
|
|
3
|
+
Edda supports PostgreSQL's LISTEN/NOTIFY mechanism for near-instant event and message delivery. This optional feature significantly reduces latency compared to polling-based delivery.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
By default, Edda uses polling to check for new events and messages. With PostgreSQL LISTEN/NOTIFY enabled:
|
|
8
|
+
|
|
9
|
+
- **Event delivery**: Near-instant (milliseconds) instead of polling interval
|
|
10
|
+
- **Message delivery**: Near-instant instead of polling interval
|
|
11
|
+
- **Database load**: Reduced polling queries
|
|
12
|
+
- **Fallback**: Automatic fallback to polling if notifications are missed
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
Install the `postgres-notify` extra:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Using uv
|
|
20
|
+
uv add edda-framework --extra postgres-notify
|
|
21
|
+
|
|
22
|
+
# Using pip
|
|
23
|
+
pip install "edda-framework[postgres-notify]"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This installs `asyncpg`, which is required for LISTEN/NOTIFY support.
|
|
27
|
+
|
|
28
|
+
## Configuration
|
|
29
|
+
|
|
30
|
+
### Basic Usage (Auto-detection)
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from edda import EddaApp
|
|
34
|
+
|
|
35
|
+
# LISTEN/NOTIFY is auto-detected for PostgreSQL
|
|
36
|
+
app = EddaApp(
|
|
37
|
+
service_name="demo-service",
|
|
38
|
+
db_url="postgresql://user:password@localhost/workflows",
|
|
39
|
+
)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
When using PostgreSQL, LISTEN/NOTIFY is automatically enabled if `asyncpg` is installed.
|
|
43
|
+
|
|
44
|
+
### Explicit Configuration
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from edda import EddaApp
|
|
48
|
+
|
|
49
|
+
app = EddaApp(
|
|
50
|
+
service_name="demo-service",
|
|
51
|
+
db_url="postgresql://user:password@localhost/workflows",
|
|
52
|
+
use_listen_notify=True, # Force enable
|
|
53
|
+
notify_fallback_interval=30, # Fallback polling every 30 seconds
|
|
54
|
+
)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Configuration Options
|
|
58
|
+
|
|
59
|
+
| Parameter | Type | Default | Description |
|
|
60
|
+
|-----------|------|---------|-------------|
|
|
61
|
+
| `use_listen_notify` | `bool \| None` | `None` | Notification mode: `None` = auto-detect, `True` = force enable, `False` = force disable |
|
|
62
|
+
| `notify_fallback_interval` | `int` | `30` | Fallback polling interval in seconds when NOTIFY is enabled |
|
|
63
|
+
| `max_workflows_per_batch` | `int \| "auto" \| "auto:cpu"` | `10` | Workflows per resume cycle. `"auto"` scales by queue depth, `"auto:cpu"` by CPU usage |
|
|
64
|
+
|
|
65
|
+
### Auto-detection Behavior
|
|
66
|
+
|
|
67
|
+
| Database | `use_listen_notify=None` | `use_listen_notify=True` | `use_listen_notify=False` |
|
|
68
|
+
|----------|--------------------------|--------------------------|---------------------------|
|
|
69
|
+
| PostgreSQL | Enabled (if asyncpg installed) | Enabled (error if asyncpg missing) | Disabled (polling only) |
|
|
70
|
+
| MySQL | Disabled | Error | Disabled |
|
|
71
|
+
| SQLite | Disabled | Error | Disabled |
|
|
72
|
+
|
|
73
|
+
## How It Works
|
|
74
|
+
|
|
75
|
+
### Architecture
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
┌─────────────────┐ NOTIFY ┌─────────────────┐
|
|
79
|
+
│ Worker Pod 1 │ <────────────── │ PostgreSQL │
|
|
80
|
+
│ (Edda App) │ │ Database │
|
|
81
|
+
└─────────────────┘ └─────────────────┘
|
|
82
|
+
│ │
|
|
83
|
+
│ LISTEN │
|
|
84
|
+
└───────────────────────────────────┘
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
1. **Dedicated Connection**: Edda maintains a separate asyncpg connection for LISTEN/NOTIFY
|
|
88
|
+
2. **Channel Subscription**: Subscribes to notification channels on startup
|
|
89
|
+
3. **Instant Wakeup**: When a notification arrives, waiting workflows are immediately resumed
|
|
90
|
+
4. **Fallback Polling**: Periodic polling ensures no notifications are missed
|
|
91
|
+
|
|
92
|
+
### Notification Channels
|
|
93
|
+
|
|
94
|
+
Edda uses the following PostgreSQL channels:
|
|
95
|
+
|
|
96
|
+
- `edda_workflow_resume`: Notifies when workflows should be resumed
|
|
97
|
+
- `edda_outbox_ready`: Notifies when outbox events are ready for relay
|
|
98
|
+
|
|
99
|
+
## Performance Comparison
|
|
100
|
+
|
|
101
|
+
| Metric | Polling Only | With LISTEN/NOTIFY |
|
|
102
|
+
|--------|--------------|-------------------|
|
|
103
|
+
| Event delivery latency | 0.5-1s (polling interval) | ~10-50ms |
|
|
104
|
+
| Message delivery latency | 0.5-1s | ~10-50ms |
|
|
105
|
+
| Database queries per idle workflow | Every 1s | Every 30s (fallback only) |
|
|
106
|
+
| Connection overhead | 1 per pool | +1 dedicated LISTEN connection |
|
|
107
|
+
|
|
108
|
+
## Reliability Features
|
|
109
|
+
|
|
110
|
+
### Automatic Reconnection
|
|
111
|
+
|
|
112
|
+
The LISTEN connection automatically reconnects on failure with configurable retry settings.
|
|
113
|
+
|
|
114
|
+
### Fallback Polling
|
|
115
|
+
|
|
116
|
+
Even with NOTIFY enabled, Edda maintains fallback polling:
|
|
117
|
+
|
|
118
|
+
- **Default interval**: 30 seconds (`notify_fallback_interval`)
|
|
119
|
+
- **Purpose**: Catch any missed notifications
|
|
120
|
+
- **Behavior**: Polling runs in parallel with NOTIFY
|
|
121
|
+
|
|
122
|
+
## Troubleshooting
|
|
123
|
+
|
|
124
|
+
### asyncpg Not Installed
|
|
125
|
+
|
|
126
|
+
If you see a warning about asyncpg not being installed:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
WARNING: asyncpg not installed, falling back to polling-only mode.
|
|
130
|
+
Install with: pip install edda-framework[postgres-notify]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Solution**: Install the postgres-notify extra.
|
|
134
|
+
|
|
135
|
+
### Force Enable on Non-PostgreSQL
|
|
136
|
+
|
|
137
|
+
If you see an error about LISTEN/NOTIFY requiring PostgreSQL:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
ValueError: use_listen_notify=True requires PostgreSQL database.
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Solution**: Use `use_listen_notify=None` (auto-detect) or `False` for non-PostgreSQL databases.
|
|
144
|
+
|
|
145
|
+
### Connection Lost
|
|
146
|
+
|
|
147
|
+
If you see reconnection messages in logs:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
INFO: Connection lost, attempting reconnection...
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
This is normal behavior. Edda automatically reconnects, and workflows continue with polling fallback during reconnection.
|
|
154
|
+
|
|
155
|
+
## Best Practices
|
|
156
|
+
|
|
157
|
+
1. **Use auto-detection**: Set `use_listen_notify=None` (default) for portability across different database backends
|
|
158
|
+
2. **Install postgres-notify in production**: For best performance with PostgreSQL
|
|
159
|
+
3. **Monitor reconnections**: Frequent reconnection warnings may indicate network issues
|
|
160
|
+
4. **Adjust fallback interval**: Lower values provide more reliability but increase database load
|
|
161
|
+
|
|
162
|
+
## Related Topics
|
|
163
|
+
|
|
164
|
+
- [Event Waiting](wait-event.md) - How workflows wait for events
|
|
165
|
+
- [Channel-based Messaging](../messages.md) - Workflow-to-workflow communication
|
|
166
|
+
- [Installation](../../getting-started/installation.md) - Database setup
|
|
@@ -38,6 +38,9 @@ uv add edda-framework --extra mysql
|
|
|
38
38
|
# With Viewer UI (workflow visualization)
|
|
39
39
|
uv add edda-framework --extra viewer
|
|
40
40
|
|
|
41
|
+
# With PostgreSQL instant notifications (LISTEN/NOTIFY)
|
|
42
|
+
uv add edda-framework --extra postgres-notify
|
|
43
|
+
|
|
41
44
|
# All extras (PostgreSQL + MySQL + Viewer UI)
|
|
42
45
|
uv add edda-framework --extra postgresql --extra mysql --extra viewer
|
|
43
46
|
```
|
|
@@ -48,6 +51,7 @@ uv add edda-framework --extra postgresql --extra mysql --extra viewer
|
|
|
48
51
|
- **postgresql**: `asyncpg` driver for PostgreSQL
|
|
49
52
|
- **mysql**: `aiomysql` driver for MySQL
|
|
50
53
|
- **viewer**: `nicegui` and `httpx` for workflow visualization UI
|
|
54
|
+
- **postgres-notify**: `asyncpg` driver for PostgreSQL LISTEN/NOTIFY instant notifications
|
|
51
55
|
|
|
52
56
|
### Using pip
|
|
53
57
|
|
|
@@ -66,6 +70,9 @@ pip install "edda-framework[mysql]"
|
|
|
66
70
|
# With Viewer UI
|
|
67
71
|
pip install "edda-framework[viewer]"
|
|
68
72
|
|
|
73
|
+
# With PostgreSQL instant notifications
|
|
74
|
+
pip install "edda-framework[postgres-notify]"
|
|
75
|
+
|
|
69
76
|
# All extras
|
|
70
77
|
pip install "edda-framework[postgresql,mysql,viewer]"
|
|
71
78
|
```
|
|
@@ -244,6 +251,44 @@ app = EddaApp(
|
|
|
244
251
|
)
|
|
245
252
|
```
|
|
246
253
|
|
|
254
|
+
#### Enabling Instant Notifications (LISTEN/NOTIFY)
|
|
255
|
+
|
|
256
|
+
For near-instant event and message delivery, enable PostgreSQL LISTEN/NOTIFY:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Install the postgres-notify extra
|
|
260
|
+
uv add edda-framework --extra postgres-notify
|
|
261
|
+
# or
|
|
262
|
+
pip install "edda-framework[postgres-notify]"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
from edda import EddaApp
|
|
267
|
+
|
|
268
|
+
app = EddaApp(
|
|
269
|
+
service_name="demo-service",
|
|
270
|
+
db_url="postgresql://user:password@localhost/edda_workflows",
|
|
271
|
+
use_listen_notify=True, # Enable LISTEN/NOTIFY (auto-detected by default)
|
|
272
|
+
notify_fallback_interval=30, # Fallback polling interval in seconds
|
|
273
|
+
)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Configuration options:**
|
|
277
|
+
|
|
278
|
+
| Parameter | Type | Default | Description |
|
|
279
|
+
|-----------|------|---------|-------------|
|
|
280
|
+
| `use_listen_notify` | `bool \| None` | `None` | `None` = auto-detect (enabled for PostgreSQL), `True` = force enable, `False` = force disable |
|
|
281
|
+
| `notify_fallback_interval` | `int` | `30` | Fallback polling interval in seconds when NOTIFY is enabled |
|
|
282
|
+
|
|
283
|
+
**Benefits:**
|
|
284
|
+
|
|
285
|
+
- Near-instant event delivery (milliseconds vs. seconds with polling)
|
|
286
|
+
- Reduced database load (fewer polling queries)
|
|
287
|
+
- Automatic fallback to polling if NOTIFY fails
|
|
288
|
+
- Automatic reconnection on connection loss
|
|
289
|
+
|
|
290
|
+
See [PostgreSQL LISTEN/NOTIFY](../core-features/events/postgres-notify.md) for detailed documentation.
|
|
291
|
+
|
|
247
292
|
### MySQL
|
|
248
293
|
|
|
249
294
|
1. **Install MySQL** (if not already installed)
|
|
@@ -27,6 +27,7 @@ Edda is a lightweight durable execution framework for Python that runs as a **li
|
|
|
27
27
|
- ☁️ **CloudEvents Support**: Native support for CloudEvents protocol
|
|
28
28
|
- ⏱️ **Event & Timer Waiting**: Free up worker resources while waiting for events or timers, resume on any available worker
|
|
29
29
|
- 📬 **Message Passing**: Channel-based messaging (broadcast/competing modes) and direct workflow-to-workflow communication
|
|
30
|
+
- ⚡ **Instant Notifications**: Optional PostgreSQL LISTEN/NOTIFY for near-instant event delivery
|
|
30
31
|
|
|
31
32
|
## Use Cases
|
|
32
33
|
|
|
@@ -220,9 +220,21 @@ The Viewer UI provides:
|
|
|
220
220
|
- ✅ **Hybrid Diagram**: Visual workflow graph (AST + execution history)
|
|
221
221
|
- ✅ **Start Workflows**: Launch workflows from the UI with auto-generated forms
|
|
222
222
|
- ✅ **Cancel Workflows**: Cancel running or waiting workflows
|
|
223
|
-
- ✅ **Filter & Search**: Find specific workflows by status, name, or
|
|
223
|
+
- ✅ **Filter & Search**: Find specific workflows by status, name, ID, or input parameters
|
|
224
224
|
- ✅ **Real-time Updates**: Auto-refresh workflow status
|
|
225
225
|
|
|
226
|
+
### Input Parameter Search
|
|
227
|
+
|
|
228
|
+
Filter workflow instances by their input data values using the Input Key and Input Value fields:
|
|
229
|
+
|
|
230
|
+
1. **Input Key**: JSON path to the field (e.g., `order_id` or `input.order_id` for nested data)
|
|
231
|
+
2. **Input Value**: Expected value to match (exact match)
|
|
232
|
+
|
|
233
|
+
**Example:** To find workflows with input `{"input": {"order_id": "ORD-123"}}`:
|
|
234
|
+
|
|
235
|
+
- Input Key: `input.order_id`
|
|
236
|
+
- Input Value: `ORD-123`
|
|
237
|
+
|
|
226
238
|
## Troubleshooting
|
|
227
239
|
|
|
228
240
|
### Viewer Dependencies Not Installed
|