conductor-python 1.3.10__tar.gz → 1.4.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.
- {conductor_python-1.3.10 → conductor_python-1.4.0}/PKG-INFO +67 -9
- {conductor_python-1.3.10 → conductor_python-1.4.0}/README.md +63 -5
- {conductor_python-1.3.10 → conductor_python-1.4.0}/pyproject.toml +9 -5
- conductor_python-1.4.0/src/conductor/client/__init__.py +30 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/async_task_runner.py +93 -7
- conductor_python-1.4.0/src/conductor/client/automator/lease_tracker.py +224 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/task_handler.py +63 -15
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/task_runner.py +210 -25
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/configuration/configuration.py +12 -1
- conductor_python-1.4.0/src/conductor/client/configuration/settings/metrics_settings.py +151 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/workflow_resource_api.py +6 -2
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api_client.py +69 -28
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/async_api_client.py +43 -20
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/async_rest.py +37 -33
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/rest.py +187 -67
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_base_client.py +9 -2
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_workflow_client.py +48 -5
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes_clients.py +14 -3
- conductor_python-1.4.0/src/conductor/client/telemetry/canonical_metrics_collector.py +242 -0
- conductor_python-1.4.0/src/conductor/client/telemetry/legacy_metrics_collector.py +324 -0
- conductor_python-1.4.0/src/conductor/client/telemetry/metrics_collector.py +38 -0
- conductor_python-1.4.0/src/conductor/client/telemetry/metrics_collector_base.py +504 -0
- conductor_python-1.4.0/src/conductor/client/telemetry/metrics_factory.py +62 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/telemetry/model/metric_documentation.py +12 -1
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/telemetry/model/metric_label.py +1 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/telemetry/model/metric_name.py +9 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker.py +3 -1
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker_config.py +10 -2
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker_task.py +14 -4
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/executor/workflow_executor.py +22 -6
- conductor_python-1.3.10/src/conductor/client/configuration/settings/metrics_settings.py +0 -59
- conductor_python-1.3.10/src/conductor/client/telemetry/metrics_collector.py +0 -927
- conductor_python-1.3.10/src/conductor/client/workflow/task/llm_tasks/utils/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/__init__.py +0 -0
- {conductor_python-1.3.10/src/conductor/client → conductor_python-1.4.0/src/conductor/client/ai}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/ai/configuration.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/ai/integrations.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/ai/orchestrator.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/authorization_client.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/ai → conductor_python-1.4.0/src/conductor/client/automator}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/json_schema_generator.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/utils.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/automator → conductor_python-1.4.0/src/conductor/client/configuration}/__init__.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/configuration → conductor_python-1.4.0/src/conductor/client/configuration/settings}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/configuration/settings/authentication_settings.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/context/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/context/task_context.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/conductor_event.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/event_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/event_dispatcher.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/listener_register.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/listeners.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/configuration/settings → conductor_python-1.4.0/src/conductor/client/event/queue}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/queue/kafka_queue_configuration.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/queue/queue_configuration.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/queue/queue_worker_configuration.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/sync_event_dispatcher.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/sync_listener_register.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/task_events.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/task_runner_events.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/workflow_events.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/event/queue → conductor_python-1.4.0/src/conductor/client/exceptions}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/exceptions/api_error.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/exceptions/api_exception_handler.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/exceptions → conductor_python-1.4.0/src/conductor/client/helpers}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/helpers/helper.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/helpers → conductor_python-1.4.0/src/conductor/client/http}/__init__.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/http → conductor_python-1.4.0/src/conductor/client/http/api}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/application_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/async_task_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/authorization_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/event_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/gateway_auth_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/group_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/integration_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/metadata_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/prompt_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/role_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/scheduler_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/schema_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/secret_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/service_registry_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/task_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/token_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/user_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/workflow_bulk_resource_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/action.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/auditable.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/authentication_config.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/authorization_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/bulk_response.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/circuit_breaker_transition_response.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/conductor_application.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/conductor_user.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/correlation_ids_search_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/create_or_update_application_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/create_or_update_role_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/event_handler.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/external_storage_location.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/generate_token_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/group.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/health.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/health_check_status.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration_api.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration_api_update.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration_def.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration_update.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/permission.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/poll_data.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/prompt_template.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/prompt_test_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/proto_registry_entry.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/rate_limit.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/request_param.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/rerun_workflow_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/response.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/role.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/save_schedule_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/schema_def.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/scrollable_search_result_workflow_summary.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_task_summary.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_workflow.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_workflow_schedule_execution_model.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_workflow_summary.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/service_method.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/service_registry.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/signal_response.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/skip_task_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/start_workflow.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/start_workflow_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/state_change_event.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/sub_workflow_params.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/subject_ref.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/tag_object.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/tag_string.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/target_ref.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_def.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_details.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_exec_log.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_result.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_result_status.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_summary.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/terminate_workflow.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/token.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/update_workflow_variables.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/upsert_group_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/upsert_user_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_def.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_message.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_run.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_schedule.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_schedule_execution_model.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_state_update.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_status.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_summary.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_tag.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_test_request.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/thread.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/integration_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/metadata_client.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/http/api → conductor_python-1.4.0/src/conductor/client/orkes}/__init__.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/orkes → conductor_python-1.4.0/src/conductor/client/orkes/api}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/api/tags_api.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/orkes/api → conductor_python-1.4.0/src/conductor/client/orkes/models}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/access_key.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/access_key_status.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/access_type.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/created_access_key.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/granted_permission.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/metadata_tag.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/ratelimit_tag.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_authorization_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_integration_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_metadata_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_prompt_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_scheduler_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_schema_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_secret_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_service_registry_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_task_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/prompt_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/scheduler_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/schema_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/secret_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/service_registry_client.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/task_client.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/orkes/models → conductor_python-1.4.0/src/conductor/client/telemetry}/__init__.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/telemetry → conductor_python-1.4.0/src/conductor/client/telemetry/model}/__init__.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/telemetry/model → conductor_python-1.4.0/src/conductor/client/worker}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/exception.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker_interface.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker_loader.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/worker → conductor_python-1.4.0/src/conductor/client/workflow}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/conductor_workflow.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/workflow → conductor_python-1.4.0/src/conductor/client/workflow/executor}/__init__.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/workflow/executor → conductor_python-1.4.0/src/conductor/client/workflow/task}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/do_while_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/dynamic_fork_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/dynamic_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/event_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/fork_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/get_document.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/http_poll_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/http_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/human_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/inline.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/javascript_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/join_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/json_jq_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/kafka_publish.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/kafka_publish_input.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/call_mcp_tool.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/chat_message.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/generate_audio.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/generate_image.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/list_mcp_tools.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_chat_complete.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_generate_embeddings.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_index_documents.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_index_text.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_query_embeddings.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_search_embeddings.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_search_index.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_store_embeddings.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_text_complete.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/tool_call.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/tool_spec.py +0 -0
- {conductor_python-1.3.10/src/conductor/client/workflow/task → conductor_python-1.4.0/src/conductor/client/workflow/task/llm_tasks/utils}/__init__.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/utils/embedding_model.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/utils/prompt.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/pull_workflow_messages_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/set_variable_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/simple_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/start_workflow_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/sub_workflow_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/switch_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/task_type.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/terminate_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/timeout_policy.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/wait_for_webhook_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/wait_task.py +0 -0
- {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow_client.py +0 -0
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conductor-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Python SDK for working with https://github.com/conductor-oss/conductor
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Author: Orkes
|
|
7
7
|
Author-email: developers@orkes.io
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Intended Audience :: System Administrators
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -27,10 +26,11 @@ Requires-Dist: h2 (>=4.1.0)
|
|
|
27
26
|
Requires-Dist: httpx[http2] (>=0.26.0)
|
|
28
27
|
Requires-Dist: prometheus-client (>=0.13.1)
|
|
29
28
|
Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
|
|
30
|
-
Requires-Dist: requests (>=2.
|
|
29
|
+
Requires-Dist: requests (>=2.33.0)
|
|
31
30
|
Requires-Dist: shortuuid (>=1.0.11)
|
|
32
31
|
Requires-Dist: six (>=1.10)
|
|
33
32
|
Requires-Dist: typing-extensions (>=4.2.0)
|
|
33
|
+
Requires-Dist: urllib3 (>=2.6.3)
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
|
|
36
36
|
# Python SDK for Conductor
|
|
@@ -54,6 +54,7 @@ If you find [Conductor](https://github.com/conductor-oss/conductor) useful, plea
|
|
|
54
54
|
* [Workers: Sync and Async](#workers-sync-and-async)
|
|
55
55
|
* [Workflows with HTTP Calls and Waits](#workflows-with-http-calls-and-waits)
|
|
56
56
|
* [Long-Running Tasks with TaskContext](#long-running-tasks-with-taskcontext)
|
|
57
|
+
* [Lease Extension for Long-Running Tasks](#lease-extension-for-long-running-tasks)
|
|
57
58
|
* [Monitoring with Metrics](#monitoring-with-metrics)
|
|
58
59
|
* [Managing Workflow Executions](#managing-workflow-executions)
|
|
59
60
|
* [AI & LLM Workflows](#ai--llm-workflows)
|
|
@@ -140,7 +141,7 @@ Create a `quickstart.py` with the following:
|
|
|
140
141
|
```python
|
|
141
142
|
from conductor.client.automator.task_handler import TaskHandler
|
|
142
143
|
from conductor.client.configuration.configuration import Configuration
|
|
143
|
-
from conductor.client.orkes_clients import OrkesClients
|
|
144
|
+
from conductor.client.orkes_clients import ConductorClients # OrkesClients is an alias for the same class
|
|
144
145
|
from conductor.client.workflow.conductor_workflow import ConductorWorkflow
|
|
145
146
|
from conductor.client.worker.worker_task import worker_task
|
|
146
147
|
|
|
@@ -155,7 +156,7 @@ def main():
|
|
|
155
156
|
# Configure the SDK (reads CONDUCTOR_SERVER_URL / CONDUCTOR_AUTH_* from env).
|
|
156
157
|
config = Configuration()
|
|
157
158
|
|
|
158
|
-
clients =
|
|
159
|
+
clients = ConductorClients(configuration=config)
|
|
159
160
|
executor = clients.get_workflow_executor()
|
|
160
161
|
|
|
161
162
|
# Build a workflow with the >> operator.
|
|
@@ -166,6 +167,8 @@ def main():
|
|
|
166
167
|
workflow.register(overwrite=True)
|
|
167
168
|
|
|
168
169
|
# Start polling for tasks (one worker subprocess per worker function).
|
|
170
|
+
# Note: scan_for_annotated_workers=True only discovers @worker_task functions that have
|
|
171
|
+
# already been imported. If workers are in a separate module, import it first.
|
|
169
172
|
with TaskHandler(configuration=config, scan_for_annotated_workers=True) as task_handler:
|
|
170
173
|
task_handler.start_processes()
|
|
171
174
|
|
|
@@ -185,6 +188,8 @@ Run it:
|
|
|
185
188
|
python quickstart.py
|
|
186
189
|
```
|
|
187
190
|
|
|
191
|
+
> **About `OrkesClients`:** This is the standard client factory for Conductor. The `Orkes` prefix reflects the implementing organization — it works identically with self-hosted OSS Conductor. No Orkes account or paid service is required.
|
|
192
|
+
|
|
188
193
|
> ### Using Orkes Conductor / Remote Server?
|
|
189
194
|
> Export your authentication credentials as well:
|
|
190
195
|
>
|
|
@@ -310,6 +315,26 @@ def batch_job(batch_id: str) -> Union[dict, TaskInProgress]:
|
|
|
310
315
|
|
|
311
316
|
See [examples/task_context_example.py](examples/task_context_example.py) for all patterns (polling, retry-aware logic, async context, input access).
|
|
312
317
|
|
|
318
|
+
### Lease Extension for Long-Running Tasks
|
|
319
|
+
|
|
320
|
+
For tasks that run longer than `responseTimeoutSeconds` (e.g., LLM inference, data pipelines, batch jobs), enable automatic lease extension. The SDK sends heartbeats at 80% of `responseTimeoutSeconds`, resetting the server's timeout timer so the task stays alive:
|
|
321
|
+
|
|
322
|
+
```python
|
|
323
|
+
from conductor.client.worker.worker_task import worker_task
|
|
324
|
+
|
|
325
|
+
@worker_task(
|
|
326
|
+
task_definition_name='train_model',
|
|
327
|
+
lease_extend_enabled=True, # Automatic heartbeat — keeps task alive
|
|
328
|
+
)
|
|
329
|
+
def train_model(dataset_id: str) -> dict:
|
|
330
|
+
"""Runs for 10 minutes, but responseTimeoutSeconds is only 60s.
|
|
331
|
+
Heartbeats at 48s intervals keep the lease alive."""
|
|
332
|
+
model = train(dataset_id)
|
|
333
|
+
return {'model_id': model.id, 'accuracy': model.accuracy}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Disabled by default. Enable per-worker via decorator, constructor, or environment variable (`conductor_worker_<task>_lease_extend_enabled=true`). See [LEASE_EXTENSION.md](LEASE_EXTENSION.md) for the full guide.
|
|
337
|
+
|
|
313
338
|
### Monitoring with Metrics
|
|
314
339
|
|
|
315
340
|
Enable Prometheus metrics with a single setting — the SDK exposes poll counts, execution times, error rates, and HTTP latency:
|
|
@@ -332,7 +357,7 @@ with TaskHandler(configuration=config, metrics_settings=metrics, scan_for_annota
|
|
|
332
357
|
curl http://localhost:8000/metrics
|
|
333
358
|
```
|
|
334
359
|
|
|
335
|
-
See [examples/metrics_example.py](examples/metrics_example.py) and [METRICS.md](METRICS.md) for
|
|
360
|
+
Legacy metrics are emitted by default. Set `WORKER_CANONICAL_METRICS=true` before starting workers to use the canonical metric catalog. See [examples/metrics_example.py](examples/metrics_example.py) and [METRICS.md](METRICS.md) for the full legacy and canonical reference.
|
|
336
361
|
|
|
337
362
|
### Managing Workflow Executions
|
|
338
363
|
|
|
@@ -341,10 +366,10 @@ Full lifecycle control — start, execute, pause, resume, terminate, retry, rest
|
|
|
341
366
|
```python
|
|
342
367
|
from conductor.client.configuration.configuration import Configuration
|
|
343
368
|
from conductor.client.http.models import StartWorkflowRequest, RerunWorkflowRequest, TaskResult
|
|
344
|
-
from conductor.client.orkes_clients import
|
|
369
|
+
from conductor.client.orkes_clients import ConductorClients
|
|
345
370
|
|
|
346
371
|
config = Configuration()
|
|
347
|
-
clients =
|
|
372
|
+
clients = ConductorClients(configuration=config)
|
|
348
373
|
workflow_client = clients.get_workflow_client()
|
|
349
374
|
task_client = clients.get_task_client()
|
|
350
375
|
executor = clients.get_workflow_executor()
|
|
@@ -442,6 +467,7 @@ See the [Examples Guide](examples/README.md) for the full catalog. Key examples:
|
|
|
442
467
|
| [kitchensink.py](examples/kitchensink.py) | All task types (HTTP, JS, JQ, Switch) | `python examples/kitchensink.py` |
|
|
443
468
|
| [workflow_ops.py](examples/workflow_ops.py) | Pause, resume, terminate, retry, restart, rerun, signal | `python examples/workflow_ops.py` |
|
|
444
469
|
| [task_context_example.py](examples/task_context_example.py) | Long-running tasks with TaskInProgress | `python examples/task_context_example.py` |
|
|
470
|
+
| [lease_extension_example.py](examples/lease_extension_example.py) | Automatic heartbeat for long-running tasks | `python examples/lease_extension_example.py` |
|
|
445
471
|
| [metrics_example.py](examples/metrics_example.py) | Prometheus metrics collection | `python examples/metrics_example.py` |
|
|
446
472
|
| [fastapi_worker_service.py](examples/fastapi_worker_service.py) | FastAPI: expose a workflow as an API (+ workers) | `uvicorn examples.fastapi_worker_service:app --port 8081 --workers 1` |
|
|
447
473
|
| [helloworld.py](examples/helloworld/helloworld.py) | Minimal hello world | `python examples/helloworld/helloworld.py` |
|
|
@@ -466,6 +492,7 @@ End-to-end examples covering all APIs for each domain:
|
|
|
466
492
|
| [Worker Design](docs/design/WORKER_DESIGN.md) | Architecture: AsyncTaskRunner vs TaskRunner, discovery, lifecycle |
|
|
467
493
|
| [Worker Guide](docs/WORKER.md) | All worker patterns (function, class, annotation, async) |
|
|
468
494
|
| [Worker Configuration](WORKER_CONFIGURATION.md) | Hierarchical environment variable configuration |
|
|
495
|
+
| [Lease Extension](LEASE_EXTENSION.md) | Automatic heartbeat for long-running tasks |
|
|
469
496
|
| [Workflow Management](docs/WORKFLOW.md) | Start, pause, resume, terminate, retry, search |
|
|
470
497
|
| [Workflow Testing](docs/WORKFLOW_TESTING.md) | Unit testing with mock outputs |
|
|
471
498
|
| [Task Management](docs/TASK_MANAGEMENT.md) | Task operations |
|
|
@@ -500,6 +527,37 @@ Yes. Conductor ensures workflows complete reliably even in the face of infrastru
|
|
|
500
527
|
|
|
501
528
|
No. While Conductor excels at asynchronous orchestration, it also supports synchronous workflow execution when immediate results are required.
|
|
502
529
|
|
|
530
|
+
**Why did `execute()` return `status: RUNNING` with no output?**
|
|
531
|
+
|
|
532
|
+
`execute()` blocks until the workflow finishes **or** `wait_for_seconds` elapses (default: 10 s),
|
|
533
|
+
whichever comes first. If it times out, you get `status='RUNNING'` — that is correct behavior,
|
|
534
|
+
not a bug.
|
|
535
|
+
|
|
536
|
+
The most common cause: your worker raised an exception. Conductor marks the task FAILED and
|
|
537
|
+
schedules a retry after `retryDelaySeconds` (default: **60 s**). The default 10 s wait expires
|
|
538
|
+
while the retry is pending, so `execute()` returns before the workflow completes.
|
|
539
|
+
|
|
540
|
+
**To fix**: increase `wait_for_seconds` to outlast the retry cycle:
|
|
541
|
+
|
|
542
|
+
```python
|
|
543
|
+
# default retryDelaySeconds is 60 — wait long enough to cover one retry
|
|
544
|
+
run = executor.execute(name='my_workflow', version=1, workflow_input={...}, wait_for_seconds=70)
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
**To debug** when a workflow is stuck:
|
|
548
|
+
|
|
549
|
+
```python
|
|
550
|
+
# Inspect task statuses and failure reasons
|
|
551
|
+
wf = executor.get_workflow(run.workflow_id, include_tasks=True)
|
|
552
|
+
for task in wf.tasks:
|
|
553
|
+
if task.status in ('FAILED', 'FAILED_WITH_TERMINAL_ERROR'):
|
|
554
|
+
print(task.reference_task_name, task.reason_for_incompletion)
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
You can also open the Conductor UI at `<server>/execution/<workflow_id>` — it shows each task's
|
|
558
|
+
status, retry count, and the worker exception message directly. Worker tracebacks are also logged
|
|
559
|
+
at ERROR level by the SDK in the `TaskHandler` process.
|
|
560
|
+
|
|
503
561
|
**Do I need to use a Conductor-specific framework?**
|
|
504
562
|
|
|
505
563
|
No. Conductor is language and framework agnostic. Use your preferred language and framework — the [SDKs](https://github.com/conductor-oss/conductor#conductor-sdks) provide native integration for Python, Java, JavaScript, Go, C#, and more.
|
|
@@ -19,6 +19,7 @@ If you find [Conductor](https://github.com/conductor-oss/conductor) useful, plea
|
|
|
19
19
|
* [Workers: Sync and Async](#workers-sync-and-async)
|
|
20
20
|
* [Workflows with HTTP Calls and Waits](#workflows-with-http-calls-and-waits)
|
|
21
21
|
* [Long-Running Tasks with TaskContext](#long-running-tasks-with-taskcontext)
|
|
22
|
+
* [Lease Extension for Long-Running Tasks](#lease-extension-for-long-running-tasks)
|
|
22
23
|
* [Monitoring with Metrics](#monitoring-with-metrics)
|
|
23
24
|
* [Managing Workflow Executions](#managing-workflow-executions)
|
|
24
25
|
* [AI & LLM Workflows](#ai--llm-workflows)
|
|
@@ -105,7 +106,7 @@ Create a `quickstart.py` with the following:
|
|
|
105
106
|
```python
|
|
106
107
|
from conductor.client.automator.task_handler import TaskHandler
|
|
107
108
|
from conductor.client.configuration.configuration import Configuration
|
|
108
|
-
from conductor.client.orkes_clients import OrkesClients
|
|
109
|
+
from conductor.client.orkes_clients import ConductorClients # OrkesClients is an alias for the same class
|
|
109
110
|
from conductor.client.workflow.conductor_workflow import ConductorWorkflow
|
|
110
111
|
from conductor.client.worker.worker_task import worker_task
|
|
111
112
|
|
|
@@ -120,7 +121,7 @@ def main():
|
|
|
120
121
|
# Configure the SDK (reads CONDUCTOR_SERVER_URL / CONDUCTOR_AUTH_* from env).
|
|
121
122
|
config = Configuration()
|
|
122
123
|
|
|
123
|
-
clients =
|
|
124
|
+
clients = ConductorClients(configuration=config)
|
|
124
125
|
executor = clients.get_workflow_executor()
|
|
125
126
|
|
|
126
127
|
# Build a workflow with the >> operator.
|
|
@@ -131,6 +132,8 @@ def main():
|
|
|
131
132
|
workflow.register(overwrite=True)
|
|
132
133
|
|
|
133
134
|
# Start polling for tasks (one worker subprocess per worker function).
|
|
135
|
+
# Note: scan_for_annotated_workers=True only discovers @worker_task functions that have
|
|
136
|
+
# already been imported. If workers are in a separate module, import it first.
|
|
134
137
|
with TaskHandler(configuration=config, scan_for_annotated_workers=True) as task_handler:
|
|
135
138
|
task_handler.start_processes()
|
|
136
139
|
|
|
@@ -150,6 +153,8 @@ Run it:
|
|
|
150
153
|
python quickstart.py
|
|
151
154
|
```
|
|
152
155
|
|
|
156
|
+
> **About `OrkesClients`:** This is the standard client factory for Conductor. The `Orkes` prefix reflects the implementing organization — it works identically with self-hosted OSS Conductor. No Orkes account or paid service is required.
|
|
157
|
+
|
|
153
158
|
> ### Using Orkes Conductor / Remote Server?
|
|
154
159
|
> Export your authentication credentials as well:
|
|
155
160
|
>
|
|
@@ -275,6 +280,26 @@ def batch_job(batch_id: str) -> Union[dict, TaskInProgress]:
|
|
|
275
280
|
|
|
276
281
|
See [examples/task_context_example.py](examples/task_context_example.py) for all patterns (polling, retry-aware logic, async context, input access).
|
|
277
282
|
|
|
283
|
+
### Lease Extension for Long-Running Tasks
|
|
284
|
+
|
|
285
|
+
For tasks that run longer than `responseTimeoutSeconds` (e.g., LLM inference, data pipelines, batch jobs), enable automatic lease extension. The SDK sends heartbeats at 80% of `responseTimeoutSeconds`, resetting the server's timeout timer so the task stays alive:
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
from conductor.client.worker.worker_task import worker_task
|
|
289
|
+
|
|
290
|
+
@worker_task(
|
|
291
|
+
task_definition_name='train_model',
|
|
292
|
+
lease_extend_enabled=True, # Automatic heartbeat — keeps task alive
|
|
293
|
+
)
|
|
294
|
+
def train_model(dataset_id: str) -> dict:
|
|
295
|
+
"""Runs for 10 minutes, but responseTimeoutSeconds is only 60s.
|
|
296
|
+
Heartbeats at 48s intervals keep the lease alive."""
|
|
297
|
+
model = train(dataset_id)
|
|
298
|
+
return {'model_id': model.id, 'accuracy': model.accuracy}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Disabled by default. Enable per-worker via decorator, constructor, or environment variable (`conductor_worker_<task>_lease_extend_enabled=true`). See [LEASE_EXTENSION.md](LEASE_EXTENSION.md) for the full guide.
|
|
302
|
+
|
|
278
303
|
### Monitoring with Metrics
|
|
279
304
|
|
|
280
305
|
Enable Prometheus metrics with a single setting — the SDK exposes poll counts, execution times, error rates, and HTTP latency:
|
|
@@ -297,7 +322,7 @@ with TaskHandler(configuration=config, metrics_settings=metrics, scan_for_annota
|
|
|
297
322
|
curl http://localhost:8000/metrics
|
|
298
323
|
```
|
|
299
324
|
|
|
300
|
-
See [examples/metrics_example.py](examples/metrics_example.py) and [METRICS.md](METRICS.md) for
|
|
325
|
+
Legacy metrics are emitted by default. Set `WORKER_CANONICAL_METRICS=true` before starting workers to use the canonical metric catalog. See [examples/metrics_example.py](examples/metrics_example.py) and [METRICS.md](METRICS.md) for the full legacy and canonical reference.
|
|
301
326
|
|
|
302
327
|
### Managing Workflow Executions
|
|
303
328
|
|
|
@@ -306,10 +331,10 @@ Full lifecycle control — start, execute, pause, resume, terminate, retry, rest
|
|
|
306
331
|
```python
|
|
307
332
|
from conductor.client.configuration.configuration import Configuration
|
|
308
333
|
from conductor.client.http.models import StartWorkflowRequest, RerunWorkflowRequest, TaskResult
|
|
309
|
-
from conductor.client.orkes_clients import
|
|
334
|
+
from conductor.client.orkes_clients import ConductorClients
|
|
310
335
|
|
|
311
336
|
config = Configuration()
|
|
312
|
-
clients =
|
|
337
|
+
clients = ConductorClients(configuration=config)
|
|
313
338
|
workflow_client = clients.get_workflow_client()
|
|
314
339
|
task_client = clients.get_task_client()
|
|
315
340
|
executor = clients.get_workflow_executor()
|
|
@@ -407,6 +432,7 @@ See the [Examples Guide](examples/README.md) for the full catalog. Key examples:
|
|
|
407
432
|
| [kitchensink.py](examples/kitchensink.py) | All task types (HTTP, JS, JQ, Switch) | `python examples/kitchensink.py` |
|
|
408
433
|
| [workflow_ops.py](examples/workflow_ops.py) | Pause, resume, terminate, retry, restart, rerun, signal | `python examples/workflow_ops.py` |
|
|
409
434
|
| [task_context_example.py](examples/task_context_example.py) | Long-running tasks with TaskInProgress | `python examples/task_context_example.py` |
|
|
435
|
+
| [lease_extension_example.py](examples/lease_extension_example.py) | Automatic heartbeat for long-running tasks | `python examples/lease_extension_example.py` |
|
|
410
436
|
| [metrics_example.py](examples/metrics_example.py) | Prometheus metrics collection | `python examples/metrics_example.py` |
|
|
411
437
|
| [fastapi_worker_service.py](examples/fastapi_worker_service.py) | FastAPI: expose a workflow as an API (+ workers) | `uvicorn examples.fastapi_worker_service:app --port 8081 --workers 1` |
|
|
412
438
|
| [helloworld.py](examples/helloworld/helloworld.py) | Minimal hello world | `python examples/helloworld/helloworld.py` |
|
|
@@ -431,6 +457,7 @@ End-to-end examples covering all APIs for each domain:
|
|
|
431
457
|
| [Worker Design](docs/design/WORKER_DESIGN.md) | Architecture: AsyncTaskRunner vs TaskRunner, discovery, lifecycle |
|
|
432
458
|
| [Worker Guide](docs/WORKER.md) | All worker patterns (function, class, annotation, async) |
|
|
433
459
|
| [Worker Configuration](WORKER_CONFIGURATION.md) | Hierarchical environment variable configuration |
|
|
460
|
+
| [Lease Extension](LEASE_EXTENSION.md) | Automatic heartbeat for long-running tasks |
|
|
434
461
|
| [Workflow Management](docs/WORKFLOW.md) | Start, pause, resume, terminate, retry, search |
|
|
435
462
|
| [Workflow Testing](docs/WORKFLOW_TESTING.md) | Unit testing with mock outputs |
|
|
436
463
|
| [Task Management](docs/TASK_MANAGEMENT.md) | Task operations |
|
|
@@ -465,6 +492,37 @@ Yes. Conductor ensures workflows complete reliably even in the face of infrastru
|
|
|
465
492
|
|
|
466
493
|
No. While Conductor excels at asynchronous orchestration, it also supports synchronous workflow execution when immediate results are required.
|
|
467
494
|
|
|
495
|
+
**Why did `execute()` return `status: RUNNING` with no output?**
|
|
496
|
+
|
|
497
|
+
`execute()` blocks until the workflow finishes **or** `wait_for_seconds` elapses (default: 10 s),
|
|
498
|
+
whichever comes first. If it times out, you get `status='RUNNING'` — that is correct behavior,
|
|
499
|
+
not a bug.
|
|
500
|
+
|
|
501
|
+
The most common cause: your worker raised an exception. Conductor marks the task FAILED and
|
|
502
|
+
schedules a retry after `retryDelaySeconds` (default: **60 s**). The default 10 s wait expires
|
|
503
|
+
while the retry is pending, so `execute()` returns before the workflow completes.
|
|
504
|
+
|
|
505
|
+
**To fix**: increase `wait_for_seconds` to outlast the retry cycle:
|
|
506
|
+
|
|
507
|
+
```python
|
|
508
|
+
# default retryDelaySeconds is 60 — wait long enough to cover one retry
|
|
509
|
+
run = executor.execute(name='my_workflow', version=1, workflow_input={...}, wait_for_seconds=70)
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**To debug** when a workflow is stuck:
|
|
513
|
+
|
|
514
|
+
```python
|
|
515
|
+
# Inspect task statuses and failure reasons
|
|
516
|
+
wf = executor.get_workflow(run.workflow_id, include_tasks=True)
|
|
517
|
+
for task in wf.tasks:
|
|
518
|
+
if task.status in ('FAILED', 'FAILED_WITH_TERMINAL_ERROR'):
|
|
519
|
+
print(task.reference_task_name, task.reason_for_incompletion)
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
You can also open the Conductor UI at `<server>/execution/<workflow_id>` — it shows each task's
|
|
523
|
+
status, retry count, and the worker exception message directly. Worker tracebacks are also logged
|
|
524
|
+
at ERROR level by the SDK in the `TaskHandler` process.
|
|
525
|
+
|
|
468
526
|
**Do I need to use a Conductor-specific framework?**
|
|
469
527
|
|
|
470
528
|
No. Conductor is language and framework agnostic. Use your preferred language and framework — the [SDKs](https://github.com/conductor-oss/conductor#conductor-sdks) provide native integration for Python, Java, JavaScript, Go, C#, and more.
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "conductor-python"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.4.0" # Do not change! Placeholder. Real version injected during build (edited)
|
|
8
8
|
description = "Python SDK for working with https://github.com/conductor-oss/conductor"
|
|
9
9
|
authors = ["Orkes <developers@orkes.io>"]
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -23,11 +23,11 @@ classifiers = [
|
|
|
23
23
|
]
|
|
24
24
|
|
|
25
25
|
[tool.poetry.dependencies]
|
|
26
|
-
python = ">=3.
|
|
26
|
+
python = ">=3.10"
|
|
27
27
|
certifi = ">=14.05.14"
|
|
28
28
|
prometheus-client = ">=0.13.1"
|
|
29
29
|
six = ">=1.10"
|
|
30
|
-
requests = ">=2.
|
|
30
|
+
requests = ">=2.33.0"
|
|
31
31
|
typing-extensions = ">=4.2.0"
|
|
32
32
|
astor = ">=0.8.1"
|
|
33
33
|
shortuuid = ">=1.0.11"
|
|
@@ -36,6 +36,7 @@ deprecated = ">=1.2.14"
|
|
|
36
36
|
python-dateutil = "^2.8.2"
|
|
37
37
|
httpx = {version = ">=0.26.0", extras = ["http2"]}
|
|
38
38
|
h2 = ">=4.1.0"
|
|
39
|
+
urllib3 = ">=2.6.3"
|
|
39
40
|
|
|
40
41
|
[tool.poetry.group.dev.dependencies]
|
|
41
42
|
pylint = ">=2.17.5"
|
|
@@ -44,10 +45,13 @@ pytest-cov = ">=4.1.0"
|
|
|
44
45
|
ruff = "^0.12.0"
|
|
45
46
|
pre-commit = "^4.2.0"
|
|
46
47
|
setuptools = "^80.9.0"
|
|
47
|
-
pytest = "^
|
|
48
|
+
pytest = "^9.0.3"
|
|
49
|
+
pygments = ">=2.20.0"
|
|
50
|
+
filelock = ">=3.20.3"
|
|
51
|
+
virtualenv = ">=20.36.1"
|
|
48
52
|
|
|
49
53
|
[tool.ruff]
|
|
50
|
-
target-version = "
|
|
54
|
+
target-version = "py310"
|
|
51
55
|
line-length = 100
|
|
52
56
|
src = ["src"]
|
|
53
57
|
extend-exclude = [
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Convenience re-exports for common symbols
|
|
2
|
+
# Allows: from conductor.client import Configuration, TaskHandler, ...
|
|
3
|
+
from conductor.client.configuration.configuration import Configuration
|
|
4
|
+
from conductor.client.automator.task_handler import TaskHandler
|
|
5
|
+
from conductor.client.automator.task_runner import TaskRunner
|
|
6
|
+
from conductor.client.orkes_clients import OrkesClients, ConductorClients
|
|
7
|
+
from conductor.client.workflow.conductor_workflow import ConductorWorkflow
|
|
8
|
+
from conductor.client.workflow.executor.workflow_executor import WorkflowExecutor
|
|
9
|
+
from conductor.client.worker.worker_task import worker_task
|
|
10
|
+
from conductor.client.worker.worker_interface import WorkerInterface
|
|
11
|
+
from conductor.client.http.models.task import Task
|
|
12
|
+
from conductor.client.http.models.task_result import TaskResult
|
|
13
|
+
from conductor.client.http.models.task_result_status import TaskResultStatus
|
|
14
|
+
from conductor.client.http.models.start_workflow_request import StartWorkflowRequest
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"Configuration",
|
|
18
|
+
"TaskHandler",
|
|
19
|
+
"TaskRunner",
|
|
20
|
+
"OrkesClients",
|
|
21
|
+
"ConductorClients",
|
|
22
|
+
"ConductorWorkflow",
|
|
23
|
+
"WorkflowExecutor",
|
|
24
|
+
"worker_task",
|
|
25
|
+
"WorkerInterface",
|
|
26
|
+
"Task",
|
|
27
|
+
"TaskResult",
|
|
28
|
+
"TaskResultStatus",
|
|
29
|
+
"StartWorkflowRequest",
|
|
30
|
+
]
|
|
@@ -27,11 +27,12 @@ from conductor.client.http.models.schema_def import SchemaDef, SchemaType
|
|
|
27
27
|
from conductor.client.http.rest import AuthorizationException, ApiException
|
|
28
28
|
from conductor.client.orkes.orkes_metadata_client import OrkesMetadataClient
|
|
29
29
|
from conductor.client.orkes.orkes_schema_client import OrkesSchemaClient
|
|
30
|
-
from conductor.client.telemetry.
|
|
30
|
+
from conductor.client.telemetry.metrics_factory import create_metrics_collector
|
|
31
31
|
from conductor.client.worker.worker_interface import WorkerInterface
|
|
32
32
|
from conductor.client.worker.worker_config import resolve_worker_config, get_worker_config_oneline
|
|
33
33
|
from conductor.client.worker.exception import NonRetryableException
|
|
34
34
|
from conductor.client.automator.json_schema_generator import generate_json_schema_from_function
|
|
35
|
+
from conductor.client.automator.lease_tracker import LeaseManager
|
|
35
36
|
|
|
36
37
|
logger = logging.getLogger(
|
|
37
38
|
Configuration.get_logging_formatted_name(
|
|
@@ -87,7 +88,7 @@ class AsyncTaskRunner:
|
|
|
87
88
|
|
|
88
89
|
self.metrics_collector = None
|
|
89
90
|
if metrics_settings is not None:
|
|
90
|
-
self.metrics_collector =
|
|
91
|
+
self.metrics_collector = create_metrics_collector(
|
|
91
92
|
metrics_settings
|
|
92
93
|
)
|
|
93
94
|
# Register metrics collector as event listener
|
|
@@ -112,6 +113,9 @@ class AsyncTaskRunner:
|
|
|
112
113
|
self._semaphore = None
|
|
113
114
|
self._shutdown = False # Flag to indicate graceful shutdown
|
|
114
115
|
self._use_update_v2 = True # Will be set to False if server doesn't support v2 endpoint
|
|
116
|
+
self._lease_manager = LeaseManager.get_instance()
|
|
117
|
+
self._tracked_task_ids = set() # Local set for cleanup on shutdown
|
|
118
|
+
self._sync_task_client = None # Created after fork for LeaseManager heartbeats
|
|
115
119
|
|
|
116
120
|
async def run(self) -> None:
|
|
117
121
|
"""Main async loop - runs continuously in single event loop."""
|
|
@@ -131,6 +135,17 @@ class AsyncTaskRunner:
|
|
|
131
135
|
api_client=self.async_api_client
|
|
132
136
|
)
|
|
133
137
|
|
|
138
|
+
# Create a sync TaskResourceApi for LeaseManager heartbeats
|
|
139
|
+
# (LeaseManager sends heartbeats from its own ThreadPoolExecutor)
|
|
140
|
+
from conductor.client.http.api.task_resource_api import TaskResourceApi
|
|
141
|
+
from conductor.client.http.api_client import ApiClient
|
|
142
|
+
self._sync_task_client = TaskResourceApi(
|
|
143
|
+
ApiClient(
|
|
144
|
+
configuration=self.configuration,
|
|
145
|
+
metrics_collector=self.metrics_collector
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
|
|
134
149
|
# Create semaphore in the event loop (must be created within the loop)
|
|
135
150
|
self._semaphore = asyncio.Semaphore(self._max_workers)
|
|
136
151
|
|
|
@@ -166,6 +181,11 @@ class AsyncTaskRunner:
|
|
|
166
181
|
"""Clean up async resources."""
|
|
167
182
|
logger.debug("Cleaning up AsyncTaskRunner resources...")
|
|
168
183
|
|
|
184
|
+
# Untrack all tasks this runner was tracking from the shared LeaseManager
|
|
185
|
+
for task_id in list(self._tracked_task_ids):
|
|
186
|
+
self._lease_manager.untrack(task_id)
|
|
187
|
+
self._tracked_task_ids.clear()
|
|
188
|
+
|
|
169
189
|
# Cancel any running tasks (EAFP style)
|
|
170
190
|
try:
|
|
171
191
|
for task in list(self._running_tasks):
|
|
@@ -182,6 +202,13 @@ class AsyncTaskRunner:
|
|
|
182
202
|
except (IOError, OSError) as e:
|
|
183
203
|
logger.warning(f"Error closing async client: {e}")
|
|
184
204
|
|
|
205
|
+
# Close sync HTTP client used for lease heartbeats
|
|
206
|
+
if self._sync_task_client:
|
|
207
|
+
try:
|
|
208
|
+
self._sync_task_client.api_client.rest_client.connection.close()
|
|
209
|
+
except Exception:
|
|
210
|
+
pass
|
|
211
|
+
|
|
185
212
|
# Clear event listeners
|
|
186
213
|
self.event_dispatcher = None
|
|
187
214
|
|
|
@@ -227,7 +254,18 @@ class AsyncTaskRunner:
|
|
|
227
254
|
output_schema_name = None
|
|
228
255
|
schema_registry_available = True
|
|
229
256
|
|
|
230
|
-
if
|
|
257
|
+
# Check if schema registration is enabled for this worker
|
|
258
|
+
register_schema = getattr(self.worker, 'register_schema', False)
|
|
259
|
+
# Also check global Configuration default
|
|
260
|
+
if hasattr(self.configuration, 'register_schema') and self.configuration.register_schema is not None:
|
|
261
|
+
# Worker-level setting takes precedence if explicitly set (not default)
|
|
262
|
+
if not hasattr(self.worker, 'register_schema'):
|
|
263
|
+
register_schema = self.configuration.register_schema
|
|
264
|
+
|
|
265
|
+
if not register_schema:
|
|
266
|
+
logger.debug(f"Schema registration disabled for {task_name} (register_schema=False)")
|
|
267
|
+
|
|
268
|
+
if register_schema and hasattr(self.worker, 'execute_function'):
|
|
231
269
|
logger.debug(f"Generating JSON schemas from function signature...")
|
|
232
270
|
# Pass strict_schema flag to control additionalProperties
|
|
233
271
|
strict_mode = getattr(self.worker, 'strict_schema', False)
|
|
@@ -309,6 +347,8 @@ class AsyncTaskRunner:
|
|
|
309
347
|
logger.debug(f"Could not register schemas for {task_name}: {e}")
|
|
310
348
|
else:
|
|
311
349
|
logger.debug(f" ⚠ No schemas generated (unable to analyze function signature)")
|
|
350
|
+
elif not register_schema:
|
|
351
|
+
pass # Already logged above
|
|
312
352
|
else:
|
|
313
353
|
logger.debug(f" ⚠ Class-based worker (no execute_function) - registering task without schemas")
|
|
314
354
|
|
|
@@ -573,15 +613,13 @@ class AsyncTaskRunner:
|
|
|
573
613
|
# Acquire semaphore for entire task lifecycle (execution + update)
|
|
574
614
|
# This ensures we never exceed thread_count tasks in any stage of processing
|
|
575
615
|
async with self._semaphore:
|
|
616
|
+
self._track_lease(task)
|
|
576
617
|
try:
|
|
577
618
|
while task is not None and not self._shutdown:
|
|
578
619
|
task_result = await self.__async_execute_task(task)
|
|
579
|
-
# If task returned TaskInProgress, don't update yet
|
|
580
|
-
if isinstance(task_result, TaskInProgress):
|
|
581
|
-
logger.debug("Task %s is in progress, will update when complete", task.task_id)
|
|
582
|
-
return
|
|
583
620
|
if task_result is None:
|
|
584
621
|
return
|
|
622
|
+
self._untrack_lease(task.task_id)
|
|
585
623
|
# Update task and get next task from v2 response
|
|
586
624
|
task = await self.__async_update_task(task_result)
|
|
587
625
|
# v2 returns the next task; if v1 was used (returns None), immediately
|
|
@@ -589,12 +627,17 @@ class AsyncTaskRunner:
|
|
|
589
627
|
if task is None and not self._use_update_v2 and not self._shutdown:
|
|
590
628
|
tasks = await self.__async_batch_poll(1)
|
|
591
629
|
task = tasks[0] if tasks else None
|
|
630
|
+
if task is not None:
|
|
631
|
+
self._track_lease(task)
|
|
592
632
|
except Exception as e:
|
|
593
633
|
logger.error(
|
|
594
634
|
"Error executing/updating task %s: %s",
|
|
595
635
|
task.task_id if task else "unknown",
|
|
596
636
|
traceback.format_exc()
|
|
597
637
|
)
|
|
638
|
+
finally:
|
|
639
|
+
if task is not None:
|
|
640
|
+
self._untrack_lease(task.task_id)
|
|
598
641
|
|
|
599
642
|
async def __async_execute_task(self, task: Task) -> TaskResult:
|
|
600
643
|
"""Execute async worker function directly (no threads, no BackgroundEventLoop)."""
|
|
@@ -820,6 +863,7 @@ class AsyncTaskRunner:
|
|
|
820
863
|
if attempt > 0:
|
|
821
864
|
# Exponential backoff: [10s, 20s, 30s] before retry
|
|
822
865
|
await asyncio.sleep(attempt * 10)
|
|
866
|
+
update_start = time.time()
|
|
823
867
|
try:
|
|
824
868
|
if self._use_update_v2:
|
|
825
869
|
next_task = await self.async_task_client.update_task_v2(body=task_result)
|
|
@@ -830,6 +874,10 @@ class AsyncTaskRunner:
|
|
|
830
874
|
task_definition_name,
|
|
831
875
|
next_task.task_id if next_task else None
|
|
832
876
|
)
|
|
877
|
+
if self.metrics_collector is not None:
|
|
878
|
+
self.metrics_collector.record_task_update_time(
|
|
879
|
+
task_definition_name, time.time() - update_start, status="SUCCESS"
|
|
880
|
+
)
|
|
833
881
|
return next_task
|
|
834
882
|
else:
|
|
835
883
|
await self.async_task_client.update_task(body=task_result)
|
|
@@ -839,6 +887,10 @@ class AsyncTaskRunner:
|
|
|
839
887
|
task_result.workflow_instance_id,
|
|
840
888
|
task_definition_name,
|
|
841
889
|
)
|
|
890
|
+
if self.metrics_collector is not None:
|
|
891
|
+
self.metrics_collector.record_task_update_time(
|
|
892
|
+
task_definition_name, time.time() - update_start, status="SUCCESS"
|
|
893
|
+
)
|
|
842
894
|
return None
|
|
843
895
|
except ApiException as e:
|
|
844
896
|
if e.status in (404, 405) and self._use_update_v2:
|
|
@@ -852,12 +904,19 @@ class AsyncTaskRunner:
|
|
|
852
904
|
# Retry immediately with v1
|
|
853
905
|
try:
|
|
854
906
|
await self.async_task_client.update_task(body=task_result)
|
|
907
|
+
if self.metrics_collector is not None:
|
|
908
|
+
self.metrics_collector.record_task_update_time(
|
|
909
|
+
task_definition_name, time.time() - update_start, status="SUCCESS"
|
|
910
|
+
)
|
|
855
911
|
return None
|
|
856
912
|
except Exception as fallback_e:
|
|
857
913
|
last_exception = fallback_e
|
|
858
914
|
continue
|
|
859
915
|
last_exception = e
|
|
860
916
|
if self.metrics_collector is not None:
|
|
917
|
+
self.metrics_collector.record_task_update_time(
|
|
918
|
+
task_definition_name, time.time() - update_start, status="FAILURE"
|
|
919
|
+
)
|
|
861
920
|
self.metrics_collector.increment_task_update_error(
|
|
862
921
|
task_definition_name, type(e)
|
|
863
922
|
)
|
|
@@ -874,6 +933,9 @@ class AsyncTaskRunner:
|
|
|
874
933
|
except Exception as e:
|
|
875
934
|
last_exception = e
|
|
876
935
|
if self.metrics_collector is not None:
|
|
936
|
+
self.metrics_collector.record_task_update_time(
|
|
937
|
+
task_definition_name, time.time() - update_start, status="FAILURE"
|
|
938
|
+
)
|
|
877
939
|
self.metrics_collector.increment_task_update_error(
|
|
878
940
|
task_definition_name, type(e)
|
|
879
941
|
)
|
|
@@ -908,6 +970,30 @@ class AsyncTaskRunner:
|
|
|
908
970
|
|
|
909
971
|
return None
|
|
910
972
|
|
|
973
|
+
# -- Lease extension (heartbeat) delegation to LeaseManager ----------------
|
|
974
|
+
|
|
975
|
+
def _track_lease(self, task) -> None:
|
|
976
|
+
"""Start tracking a task for lease extension via the shared LeaseManager."""
|
|
977
|
+
if not getattr(self.worker, 'lease_extend_enabled', False):
|
|
978
|
+
return
|
|
979
|
+
timeout = getattr(task, 'response_timeout_seconds', None) or 0
|
|
980
|
+
if timeout <= 0:
|
|
981
|
+
return
|
|
982
|
+
self._lease_manager.track(
|
|
983
|
+
task_id=task.task_id,
|
|
984
|
+
workflow_instance_id=task.workflow_instance_id,
|
|
985
|
+
response_timeout_seconds=timeout,
|
|
986
|
+
task_client=self._sync_task_client,
|
|
987
|
+
)
|
|
988
|
+
self._tracked_task_ids.add(task.task_id)
|
|
989
|
+
|
|
990
|
+
def _untrack_lease(self, task_id: str) -> None:
|
|
991
|
+
"""Stop tracking a task for lease extension."""
|
|
992
|
+
self._lease_manager.untrack(task_id)
|
|
993
|
+
self._tracked_task_ids.discard(task_id)
|
|
994
|
+
|
|
995
|
+
# --------------------------------------------------------------------------
|
|
996
|
+
|
|
911
997
|
def __set_worker_properties(self) -> None:
|
|
912
998
|
"""
|
|
913
999
|
Resolve worker configuration using hierarchical override (same as TaskRunner).
|