edda-framework 0.10.0__tar.gz → 0.12.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.10.0 → edda_framework-0.12.0}/.github/workflows/ci.yml +3 -1
- {edda_framework-0.10.0 → edda_framework-0.12.0}/.github/workflows/docs.yml +3 -1
- {edda_framework-0.10.0 → edda_framework-0.12.0}/.github/workflows/release.yml +6 -2
- edda_framework-0.12.0/.gitmodules +3 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/PKG-INFO +47 -3
- {edda_framework-0.10.0 → edda_framework-0.12.0}/README.md +43 -2
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/durable-execution/replay.md +3 -2
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/messages.md +35 -1
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/getting-started/installation.md +82 -0
- edda_framework-0.12.0/docs/integrations/mirascope.md +373 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/integrations/pydantic-rpc.md +1 -1
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/app.py +203 -35
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/channels.py +57 -12
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/context.py +24 -0
- edda_framework-0.12.0/edda/integrations/mirascope/__init__.py +78 -0
- edda_framework-0.12.0/edda/integrations/mirascope/agent.py +467 -0
- edda_framework-0.12.0/edda/integrations/mirascope/call.py +166 -0
- edda_framework-0.12.0/edda/integrations/mirascope/decorator.py +163 -0
- edda_framework-0.12.0/edda/integrations/mirascope/types.py +268 -0
- edda_framework-0.12.0/edda/migrations/mysql/20251217000000_initial_schema.sql +284 -0
- edda_framework-0.12.0/edda/migrations/postgresql/20251217000000_initial_schema.sql +284 -0
- edda_framework-0.12.0/edda/migrations/sqlite/20251217000000_initial_schema.sql +284 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/outbox/relayer.py +34 -7
- edda_framework-0.12.0/edda/storage/migrations.py +435 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/storage/models.py +2 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/storage/pg_notify.py +5 -8
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/storage/sqlalchemy_storage.py +97 -61
- edda_framework-0.12.0/examples/mirascope/__init__.py +6 -0
- edda_framework-0.12.0/examples/mirascope/durable_agent.py +421 -0
- edda_framework-0.12.0/examples/mirascope/multi_turn.py +150 -0
- edda_framework-0.12.0/examples/mirascope/simple_call.py +167 -0
- edda_framework-0.12.0/examples/mirascope/with_tools.py +198 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/pyproject.toml +16 -2
- edda_framework-0.12.0/schema/.dbmate.yml +16 -0
- edda_framework-0.12.0/schema/.git +1 -0
- edda_framework-0.12.0/schema/.gitignore +20 -0
- edda_framework-0.12.0/schema/LICENSE +21 -0
- edda_framework-0.12.0/schema/README.md +53 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/conftest.py +32 -10
- edda_framework-0.12.0/tests/integrations/mirascope/__init__.py +1 -0
- edda_framework-0.12.0/tests/integrations/mirascope/test_agent.py +403 -0
- edda_framework-0.12.0/tests/integrations/mirascope/test_call.py +183 -0
- edda_framework-0.12.0/tests/integrations/mirascope/test_decorator.py +235 -0
- edda_framework-0.12.0/tests/integrations/mirascope/test_types.py +449 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_app.py +46 -39
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_auto_migration.py +6 -1
- edda_framework-0.12.0/tests/test_channel_direct.py +329 -0
- edda_framework-0.12.0/tests/test_migrations_integration.py +211 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_pg_notify.py +5 -5
- edda_framework-0.12.0/tests/test_polling_optimization.py +1026 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/uv.lock +381 -49
- {edda_framework-0.10.0 → edda_framework-0.12.0}/zensical.toml +1 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/.gitignore +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/.python-version +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/Justfile +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/LICENSE +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/demo_app.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/api/reference.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/events/cloudevents-http-binding.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/events/postgres-notify.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/events/wait-event.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/hooks.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/retry.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/saga-compensation.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/transactional-outbox.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/workflows-activities.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/examples/ecommerce.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/examples/events.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/examples/fastapi-integration.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/examples/saga.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/examples/simple.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/getting-started/concepts.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/getting-started/first-workflow.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/getting-started/quick-start.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/index.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/integrations/mcp.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/integrations/opentelemetry.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/images/cloudevents-cli-trigger.png +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/images/compensation-execution.png +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/images/detail-page-loan-approval.png +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/images/detail-page-match-case.png +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/images/nested-pydantic-form.png +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/images/start-workflow-form-pydantic.png +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/images/wait-event-visualization.png +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/images/workflow-list-view.png +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/images/workflow-selection-dropdown.png +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/setup.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/docs/viewer-ui/visualization.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/activity.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/compensation.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/exceptions.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/hooks.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/integrations/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/integrations/mcp/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/integrations/mcp/decorators.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/integrations/mcp/server.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/integrations/opentelemetry/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/integrations/opentelemetry/hooks.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/locking.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/outbox/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/outbox/transactional.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/pydantic_utils.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/replay.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/retry.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/serialization/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/serialization/base.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/serialization/json.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/storage/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/storage/notify_base.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/storage/protocol.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/viewer_ui/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/viewer_ui/app.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/viewer_ui/components.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/viewer_ui/data_service.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/viewer_ui/theme.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/visualizer/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/visualizer/ast_analyzer.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/visualizer/mermaid_generator.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/workflow.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/edda/wsgi.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/cancellable_workflow.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/compensation_workflow.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/event_waiting_app.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/event_waiting_workflow.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/event_waiting_workflow_complete.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/long_running_loop.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/mcp/README.md +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/mcp/order_processing_mcp.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/mcp/prompts_example.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/mcp/remote_server_example.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/mcp/simple_mcp_server.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/message_passing.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/observability_with_logfire.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/observability_with_opentelemetry.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/pydantic_rpc_integration.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/pydantic_saga.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/retry_example.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/retry_with_compensation.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/simple_workflow.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/typeddict_example.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/examples/with_outbox.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/integrations/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/integrations/mcp/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/integrations/mcp/test_cancel.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/integrations/mcp/test_integration.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/integrations/mcp/test_jsonrpc.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/integrations/mcp/test_prompts.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/integrations/mcp/test_server.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/integrations/opentelemetry/__init__.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/integrations/opentelemetry/test_hooks.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_activity.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_activity_retry.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_activity_sync.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_ast_analyzer.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_atomic_wait_event.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_binary_data.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_channel_competing.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_channel_transactional.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_cloudevents_http_binding.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_compensation.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_compensation_crash_recovery.py.wip +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_concurrent_outbox.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_context.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_ctx_session.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_distributed_event_delivery.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_events.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_instance_id_routing.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_lock_race_condition.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_lock_timeout_customization.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_locking.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_message_cleanup.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_message_delivery_lock.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_messages.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_multidb_storage.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_outbox.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_pydantic_activity.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_pydantic_enum.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_pydantic_events.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_pydantic_saga.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_pydantic_utils.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_receive_timeout.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_received_event.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_recur.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_recur_cleanup.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_replay.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_retry_policy.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_saga_parameter_extraction.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_serialization.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_skip_locked.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_stale_workflow_recovery.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_storage.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_storage_mysql.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_storage_postgresql.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_transactions.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_viewer_pagination.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_viewer_pydantic_form.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_viewer_start_saga.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_wait_timer.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_workflow.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_workflow_auto_register.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_workflow_cancellation.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/tests/test_workflow_resumption.py +0 -0
- {edda_framework-0.10.0 → edda_framework-0.12.0}/viewer_app.py +0 -0
|
@@ -17,7 +17,9 @@ jobs:
|
|
|
17
17
|
|
|
18
18
|
steps:
|
|
19
19
|
- name: Checkout code
|
|
20
|
-
uses: actions/checkout@
|
|
20
|
+
uses: actions/checkout@v6
|
|
21
|
+
with:
|
|
22
|
+
submodules: true
|
|
21
23
|
|
|
22
24
|
- name: Set up uv
|
|
23
25
|
uses: astral-sh/setup-uv@v3
|
|
@@ -29,7 +31,9 @@ jobs:
|
|
|
29
31
|
run: uv sync
|
|
30
32
|
|
|
31
33
|
- name: Build package
|
|
32
|
-
run:
|
|
34
|
+
run: |
|
|
35
|
+
uv build --sdist
|
|
36
|
+
uv build --wheel
|
|
33
37
|
|
|
34
38
|
- name: Publish to PyPI
|
|
35
39
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: edda-framework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.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
|
|
@@ -44,6 +44,9 @@ Requires-Dist: testcontainers[postgres]>=4.0.0; extra == 'dev'
|
|
|
44
44
|
Requires-Dist: tsuno>=0.1.3; extra == 'dev'
|
|
45
45
|
Provides-Extra: mcp
|
|
46
46
|
Requires-Dist: mcp>=1.22.0; extra == 'mcp'
|
|
47
|
+
Provides-Extra: mirascope
|
|
48
|
+
Requires-Dist: mirascope[anthropic,google,openai]>=2.0.0a0; extra == 'mirascope'
|
|
49
|
+
Requires-Dist: pydantic-settings>=2.0.0; extra == 'mirascope'
|
|
47
50
|
Provides-Extra: mysql
|
|
48
51
|
Requires-Dist: aiomysql>=0.2.0; extra == 'mysql'
|
|
49
52
|
Provides-Extra: opentelemetry
|
|
@@ -93,6 +96,7 @@ For detailed documentation, visit [https://i2y.github.io/edda/](https://i2y.gith
|
|
|
93
96
|
- 📬 **Channel-based Messaging**: Actor-model style communication with competing (job queue) and broadcast (fan-out) modes
|
|
94
97
|
- ⚡ **Instant Notifications**: PostgreSQL LISTEN/NOTIFY for near-instant event delivery (optional)
|
|
95
98
|
- 🤖 **MCP Integration**: Expose durable workflows as AI tools via Model Context Protocol
|
|
99
|
+
- 🧠 **Mirascope Integration**: Durable LLM calls
|
|
96
100
|
- 🌍 **ASGI/WSGI Support**: Deploy with your preferred server (uvicorn, gunicorn, uWSGI)
|
|
97
101
|
|
|
98
102
|
## Use Cases
|
|
@@ -282,6 +286,46 @@ pip install "git+https://github.com/i2y/edda.git[postgresql,viewer]"
|
|
|
282
286
|
|
|
283
287
|
> **Tip**: For PostgreSQL, install the `postgres-notify` extra for near-instant event delivery using LISTEN/NOTIFY instead of polling.
|
|
284
288
|
|
|
289
|
+
### Database Schema Migration
|
|
290
|
+
|
|
291
|
+
**Automatic Migration (Default)**
|
|
292
|
+
|
|
293
|
+
Edda automatically applies database migrations at startup. No manual commands needed:
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
from edda import EddaApp
|
|
297
|
+
|
|
298
|
+
# Migrations are applied automatically
|
|
299
|
+
app = EddaApp(db_url="postgresql://user:pass@localhost/dbname")
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
This is safe in multi-worker environments - Edda handles concurrent startup gracefully.
|
|
303
|
+
|
|
304
|
+
**Manual Migration with dbmate (Optional)**
|
|
305
|
+
|
|
306
|
+
For explicit schema control, you can disable auto-migration and use [dbmate](https://github.com/amacneil/dbmate):
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
# Disable auto-migration
|
|
310
|
+
app = EddaApp(
|
|
311
|
+
db_url="postgresql://...",
|
|
312
|
+
auto_migrate=False # Use dbmate-managed schema
|
|
313
|
+
)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# Install dbmate
|
|
318
|
+
brew install dbmate # macOS
|
|
319
|
+
|
|
320
|
+
# Add schema submodule
|
|
321
|
+
git submodule add https://github.com/durax-io/schema.git schema
|
|
322
|
+
|
|
323
|
+
# Run migration manually
|
|
324
|
+
DATABASE_URL="postgresql://user:pass@localhost/dbname" dbmate -d ./schema/db/migrations/postgresql up
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
> **Note**: Edda's auto-migration uses the same SQL files as dbmate, maintaining full compatibility.
|
|
328
|
+
|
|
285
329
|
### Development Installation
|
|
286
330
|
|
|
287
331
|
If you want to contribute to Edda or modify the framework itself:
|
|
@@ -289,7 +333,7 @@ If you want to contribute to Edda or modify the framework itself:
|
|
|
289
333
|
```bash
|
|
290
334
|
# Clone repository
|
|
291
335
|
git clone https://github.com/i2y/edda.git
|
|
292
|
-
cd
|
|
336
|
+
cd edda
|
|
293
337
|
uv sync --all-extras
|
|
294
338
|
```
|
|
295
339
|
|
|
@@ -329,7 +373,7 @@ async def user_signup(ctx: WorkflowContext, email: str):
|
|
|
329
373
|
return {"status": "completed"}
|
|
330
374
|
```
|
|
331
375
|
|
|
332
|
-
**Activity IDs**: Activities are automatically identified with IDs like `"send_email:1"` for deterministic replay. Manual IDs are only needed for concurrent execution (e.g., `asyncio.gather`).
|
|
376
|
+
**Activity IDs**: Activities are automatically identified with IDs like `"send_email:1"` for deterministic replay. Manual IDs are only needed for concurrent execution (e.g., `asyncio.gather`).
|
|
333
377
|
|
|
334
378
|
### Durable Execution
|
|
335
379
|
|
|
@@ -31,6 +31,7 @@ For detailed documentation, visit [https://i2y.github.io/edda/](https://i2y.gith
|
|
|
31
31
|
- 📬 **Channel-based Messaging**: Actor-model style communication with competing (job queue) and broadcast (fan-out) modes
|
|
32
32
|
- ⚡ **Instant Notifications**: PostgreSQL LISTEN/NOTIFY for near-instant event delivery (optional)
|
|
33
33
|
- 🤖 **MCP Integration**: Expose durable workflows as AI tools via Model Context Protocol
|
|
34
|
+
- 🧠 **Mirascope Integration**: Durable LLM calls
|
|
34
35
|
- 🌍 **ASGI/WSGI Support**: Deploy with your preferred server (uvicorn, gunicorn, uWSGI)
|
|
35
36
|
|
|
36
37
|
## Use Cases
|
|
@@ -220,6 +221,46 @@ pip install "git+https://github.com/i2y/edda.git[postgresql,viewer]"
|
|
|
220
221
|
|
|
221
222
|
> **Tip**: For PostgreSQL, install the `postgres-notify` extra for near-instant event delivery using LISTEN/NOTIFY instead of polling.
|
|
222
223
|
|
|
224
|
+
### Database Schema Migration
|
|
225
|
+
|
|
226
|
+
**Automatic Migration (Default)**
|
|
227
|
+
|
|
228
|
+
Edda automatically applies database migrations at startup. No manual commands needed:
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
from edda import EddaApp
|
|
232
|
+
|
|
233
|
+
# Migrations are applied automatically
|
|
234
|
+
app = EddaApp(db_url="postgresql://user:pass@localhost/dbname")
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
This is safe in multi-worker environments - Edda handles concurrent startup gracefully.
|
|
238
|
+
|
|
239
|
+
**Manual Migration with dbmate (Optional)**
|
|
240
|
+
|
|
241
|
+
For explicit schema control, you can disable auto-migration and use [dbmate](https://github.com/amacneil/dbmate):
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
# Disable auto-migration
|
|
245
|
+
app = EddaApp(
|
|
246
|
+
db_url="postgresql://...",
|
|
247
|
+
auto_migrate=False # Use dbmate-managed schema
|
|
248
|
+
)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
# Install dbmate
|
|
253
|
+
brew install dbmate # macOS
|
|
254
|
+
|
|
255
|
+
# Add schema submodule
|
|
256
|
+
git submodule add https://github.com/durax-io/schema.git schema
|
|
257
|
+
|
|
258
|
+
# Run migration manually
|
|
259
|
+
DATABASE_URL="postgresql://user:pass@localhost/dbname" dbmate -d ./schema/db/migrations/postgresql up
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
> **Note**: Edda's auto-migration uses the same SQL files as dbmate, maintaining full compatibility.
|
|
263
|
+
|
|
223
264
|
### Development Installation
|
|
224
265
|
|
|
225
266
|
If you want to contribute to Edda or modify the framework itself:
|
|
@@ -227,7 +268,7 @@ If you want to contribute to Edda or modify the framework itself:
|
|
|
227
268
|
```bash
|
|
228
269
|
# Clone repository
|
|
229
270
|
git clone https://github.com/i2y/edda.git
|
|
230
|
-
cd
|
|
271
|
+
cd edda
|
|
231
272
|
uv sync --all-extras
|
|
232
273
|
```
|
|
233
274
|
|
|
@@ -267,7 +308,7 @@ async def user_signup(ctx: WorkflowContext, email: str):
|
|
|
267
308
|
return {"status": "completed"}
|
|
268
309
|
```
|
|
269
310
|
|
|
270
|
-
**Activity IDs**: Activities are automatically identified with IDs like `"send_email:1"` for deterministic replay. Manual IDs are only needed for concurrent execution (e.g., `asyncio.gather`).
|
|
311
|
+
**Activity IDs**: Activities are automatically identified with IDs like `"send_email:1"` for deterministic replay. Manual IDs are only needed for concurrent execution (e.g., `asyncio.gather`).
|
|
271
312
|
|
|
272
313
|
### Durable Execution
|
|
273
314
|
|
{edda_framework-0.10.0 → edda_framework-0.12.0}/docs/core-features/durable-execution/replay.md
RENAMED
|
@@ -349,7 +349,7 @@ async def resume_workflow_endpoint(instance_id: str):
|
|
|
349
349
|
|
|
350
350
|
Edda automatically recovers from crashes in two stages:
|
|
351
351
|
|
|
352
|
-
#### 3-1. Stale Lock Cleanup
|
|
352
|
+
#### 3-1. Stale Lock Cleanup
|
|
353
353
|
|
|
354
354
|
When a worker process crashes, its locks become "stale." Edda automatically cleans these up:
|
|
355
355
|
|
|
@@ -394,7 +394,7 @@ This background task starts automatically when `EddaApp` launches.
|
|
|
394
394
|
|
|
395
395
|
The `status` field indicates whether the workflow was running normally (`"running"`) or executing compensations (`"compensating"`) when it crashed.
|
|
396
396
|
|
|
397
|
-
#### 3-2. Automatic Workflow Resume
|
|
397
|
+
#### 3-2. Automatic Workflow Resume
|
|
398
398
|
|
|
399
399
|
After cleaning stale locks, Edda automatically resumes workflows with `status="running"` or `status="compensating"`:
|
|
400
400
|
|
|
@@ -586,6 +586,7 @@ async with workflow_lock(storage, instance_id, worker_id, timeout_seconds=300):
|
|
|
586
586
|
```
|
|
587
587
|
|
|
588
588
|
Features:
|
|
589
|
+
|
|
589
590
|
- **5-minute timeout** by default (prevents indefinite locks)
|
|
590
591
|
- **Worker ID tracking** (know which worker holds the lock)
|
|
591
592
|
- **Stale lock cleanup** (automatic recovery after crashes)
|
|
@@ -47,6 +47,40 @@ async def notification_service(ctx: WorkflowContext, service_id: str):
|
|
|
47
47
|
|
|
48
48
|
- `"broadcast"` (default): All subscribers receive all messages. Use for fan-out patterns like notifications.
|
|
49
49
|
- `"competing"`: Each message is processed by only one subscriber. Use for job queues and task distribution.
|
|
50
|
+
- `"direct"`: Receive messages sent via `send_to()` to this specific instance. Syntactic sugar for point-to-point messaging.
|
|
51
|
+
|
|
52
|
+
**Using `mode="direct"`**:
|
|
53
|
+
|
|
54
|
+
The `"direct"` mode simplifies receiving messages sent via `send_to()`:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
@workflow
|
|
58
|
+
async def direct_receiver(ctx: WorkflowContext, id: str):
|
|
59
|
+
# Subscribe to receive direct messages
|
|
60
|
+
await subscribe(ctx, "notifications", mode="direct")
|
|
61
|
+
|
|
62
|
+
# Wait for a message sent via send_to()
|
|
63
|
+
msg = await receive(ctx, "notifications")
|
|
64
|
+
return msg.data
|
|
65
|
+
|
|
66
|
+
@workflow
|
|
67
|
+
async def sender(ctx: WorkflowContext, receiver_id: str):
|
|
68
|
+
# Send directly to the receiver instance
|
|
69
|
+
await send_to(ctx, instance_id=receiver_id, data={"hello": "world"}, channel="notifications")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This is equivalent to manually constructing the channel name:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
# Without mode="direct" (manual approach)
|
|
76
|
+
direct_channel = f"notifications:{ctx.instance_id}"
|
|
77
|
+
await subscribe(ctx, direct_channel, mode="broadcast")
|
|
78
|
+
msg = await receive(ctx, direct_channel)
|
|
79
|
+
|
|
80
|
+
# With mode="direct" (simplified)
|
|
81
|
+
await subscribe(ctx, "notifications", mode="direct")
|
|
82
|
+
msg = await receive(ctx, "notifications")
|
|
83
|
+
```
|
|
50
84
|
|
|
51
85
|
#### `unsubscribe()`
|
|
52
86
|
|
|
@@ -202,7 +236,7 @@ async def subscribe(
|
|
|
202
236
|
|
|
203
237
|
- `ctx`: Workflow context
|
|
204
238
|
- `channel`: Channel name to subscribe to
|
|
205
|
-
- `mode`: `"broadcast"` (all subscribers receive)
|
|
239
|
+
- `mode`: `"broadcast"` (all subscribers receive), `"competing"` (one subscriber per message), or `"direct"` (receive messages from `send_to()`)
|
|
206
240
|
|
|
207
241
|
### receive()
|
|
208
242
|
|
|
@@ -310,6 +310,88 @@ app = EddaApp(
|
|
|
310
310
|
)
|
|
311
311
|
```
|
|
312
312
|
|
|
313
|
+
### Schema Migration
|
|
314
|
+
|
|
315
|
+
#### Automatic Migration (Default)
|
|
316
|
+
|
|
317
|
+
Edda automatically applies database migrations at startup. No manual commands needed:
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
from edda import EddaApp
|
|
321
|
+
|
|
322
|
+
# Migrations are applied automatically at startup
|
|
323
|
+
app = EddaApp(
|
|
324
|
+
service_name="demo-service",
|
|
325
|
+
db_url="postgresql://user:pass@localhost/dbname"
|
|
326
|
+
)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Key features:**
|
|
330
|
+
|
|
331
|
+
- **Zero configuration**: Works out of the box
|
|
332
|
+
- **Multi-worker safe**: Handles concurrent startup gracefully (race condition protected)
|
|
333
|
+
- **dbmate compatible**: Uses the same SQL files and `schema_migrations` table
|
|
334
|
+
- **Incremental**: Only applies pending migrations
|
|
335
|
+
|
|
336
|
+
#### Manual Migration with dbmate (Optional)
|
|
337
|
+
|
|
338
|
+
For explicit schema control, you can disable auto-migration and use [dbmate](https://github.com/amacneil/dbmate):
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
# Disable auto-migration
|
|
342
|
+
app = EddaApp(
|
|
343
|
+
service_name="demo-service",
|
|
344
|
+
db_url="postgresql://...",
|
|
345
|
+
auto_migrate=False # Use dbmate-managed schema
|
|
346
|
+
)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
# Install dbmate
|
|
351
|
+
brew install dbmate # macOS
|
|
352
|
+
# Linux: curl -fsSL https://github.com/amacneil/dbmate/releases/latest/download/dbmate-linux-amd64 -o /usr/local/bin/dbmate && chmod +x /usr/local/bin/dbmate
|
|
353
|
+
|
|
354
|
+
# Add schema submodule to your project
|
|
355
|
+
git submodule add https://github.com/durax-io/schema.git schema
|
|
356
|
+
|
|
357
|
+
# Run migration manually
|
|
358
|
+
DATABASE_URL="postgresql://user:pass@localhost/dbname" dbmate -d ./schema/db/migrations/postgresql up
|
|
359
|
+
|
|
360
|
+
# Check status
|
|
361
|
+
dbmate -d ./schema/db/migrations/postgresql status
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
> **Note**: Edda's auto-migration uses the same SQL files as dbmate, so you can switch between modes freely.
|
|
365
|
+
|
|
366
|
+
### Multi-Worker Configuration
|
|
367
|
+
|
|
368
|
+
When running multiple Edda workers (e.g., in Kubernetes or with multiple processes), Edda automatically coordinates background tasks using **leader election**. Only one worker runs maintenance tasks (timers, message cleanup, etc.) while others focus on workflow execution.
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
from edda import EddaApp
|
|
372
|
+
|
|
373
|
+
app = EddaApp(
|
|
374
|
+
service_name="demo-service",
|
|
375
|
+
db_url="postgresql://...",
|
|
376
|
+
# Leader election settings (optional - defaults work well for most cases)
|
|
377
|
+
leader_heartbeat_interval=15, # How often workers check/renew leadership
|
|
378
|
+
leader_lease_duration=45, # How long before a failed leader is replaced
|
|
379
|
+
)
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Configuration options:**
|
|
383
|
+
|
|
384
|
+
| Parameter | Type | Default | Description |
|
|
385
|
+
|-----------|------|---------|-------------|
|
|
386
|
+
| `leader_heartbeat_interval` | `int` | `15` | Interval in seconds for leader heartbeat |
|
|
387
|
+
| `leader_lease_duration` | `int` | `45` | Duration in seconds before leadership expires |
|
|
388
|
+
|
|
389
|
+
**Notes:**
|
|
390
|
+
|
|
391
|
+
- Default values work well for most deployments
|
|
392
|
+
- Reduce `leader_lease_duration` for faster failover (minimum: 3x heartbeat interval)
|
|
393
|
+
- Leader election uses the database for coordination (no external dependencies)
|
|
394
|
+
|
|
313
395
|
## Next Steps
|
|
314
396
|
|
|
315
397
|
- **[Quick Start](quick-start.md)**: Build your first workflow in 5 minutes
|