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.
Files changed (251) hide show
  1. {conductor_python-1.3.10 → conductor_python-1.4.0}/PKG-INFO +67 -9
  2. {conductor_python-1.3.10 → conductor_python-1.4.0}/README.md +63 -5
  3. {conductor_python-1.3.10 → conductor_python-1.4.0}/pyproject.toml +9 -5
  4. conductor_python-1.4.0/src/conductor/client/__init__.py +30 -0
  5. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/async_task_runner.py +93 -7
  6. conductor_python-1.4.0/src/conductor/client/automator/lease_tracker.py +224 -0
  7. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/task_handler.py +63 -15
  8. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/task_runner.py +210 -25
  9. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/configuration/configuration.py +12 -1
  10. conductor_python-1.4.0/src/conductor/client/configuration/settings/metrics_settings.py +151 -0
  11. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/workflow_resource_api.py +6 -2
  12. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api_client.py +69 -28
  13. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/async_api_client.py +43 -20
  14. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/async_rest.py +37 -33
  15. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/rest.py +187 -67
  16. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_base_client.py +9 -2
  17. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_workflow_client.py +48 -5
  18. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes_clients.py +14 -3
  19. conductor_python-1.4.0/src/conductor/client/telemetry/canonical_metrics_collector.py +242 -0
  20. conductor_python-1.4.0/src/conductor/client/telemetry/legacy_metrics_collector.py +324 -0
  21. conductor_python-1.4.0/src/conductor/client/telemetry/metrics_collector.py +38 -0
  22. conductor_python-1.4.0/src/conductor/client/telemetry/metrics_collector_base.py +504 -0
  23. conductor_python-1.4.0/src/conductor/client/telemetry/metrics_factory.py +62 -0
  24. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/telemetry/model/metric_documentation.py +12 -1
  25. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/telemetry/model/metric_label.py +1 -0
  26. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/telemetry/model/metric_name.py +9 -0
  27. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker.py +3 -1
  28. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker_config.py +10 -2
  29. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker_task.py +14 -4
  30. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/executor/workflow_executor.py +22 -6
  31. conductor_python-1.3.10/src/conductor/client/configuration/settings/metrics_settings.py +0 -59
  32. conductor_python-1.3.10/src/conductor/client/telemetry/metrics_collector.py +0 -927
  33. conductor_python-1.3.10/src/conductor/client/workflow/task/llm_tasks/utils/__init__.py +0 -0
  34. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/__init__.py +0 -0
  35. {conductor_python-1.3.10/src/conductor/client → conductor_python-1.4.0/src/conductor/client/ai}/__init__.py +0 -0
  36. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/ai/configuration.py +0 -0
  37. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/ai/integrations.py +0 -0
  38. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/ai/orchestrator.py +0 -0
  39. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/authorization_client.py +0 -0
  40. {conductor_python-1.3.10/src/conductor/client/ai → conductor_python-1.4.0/src/conductor/client/automator}/__init__.py +0 -0
  41. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/json_schema_generator.py +0 -0
  42. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/automator/utils.py +0 -0
  43. {conductor_python-1.3.10/src/conductor/client/automator → conductor_python-1.4.0/src/conductor/client/configuration}/__init__.py +0 -0
  44. {conductor_python-1.3.10/src/conductor/client/configuration → conductor_python-1.4.0/src/conductor/client/configuration/settings}/__init__.py +0 -0
  45. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/configuration/settings/authentication_settings.py +0 -0
  46. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/context/__init__.py +0 -0
  47. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/context/task_context.py +0 -0
  48. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/__init__.py +0 -0
  49. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/conductor_event.py +0 -0
  50. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/event_client.py +0 -0
  51. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/event_dispatcher.py +0 -0
  52. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/listener_register.py +0 -0
  53. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/listeners.py +0 -0
  54. {conductor_python-1.3.10/src/conductor/client/configuration/settings → conductor_python-1.4.0/src/conductor/client/event/queue}/__init__.py +0 -0
  55. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/queue/kafka_queue_configuration.py +0 -0
  56. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/queue/queue_configuration.py +0 -0
  57. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/queue/queue_worker_configuration.py +0 -0
  58. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/sync_event_dispatcher.py +0 -0
  59. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/sync_listener_register.py +0 -0
  60. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/task_events.py +0 -0
  61. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/task_runner_events.py +0 -0
  62. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/event/workflow_events.py +0 -0
  63. {conductor_python-1.3.10/src/conductor/client/event/queue → conductor_python-1.4.0/src/conductor/client/exceptions}/__init__.py +0 -0
  64. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/exceptions/api_error.py +0 -0
  65. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/exceptions/api_exception_handler.py +0 -0
  66. {conductor_python-1.3.10/src/conductor/client/exceptions → conductor_python-1.4.0/src/conductor/client/helpers}/__init__.py +0 -0
  67. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/helpers/helper.py +0 -0
  68. {conductor_python-1.3.10/src/conductor/client/helpers → conductor_python-1.4.0/src/conductor/client/http}/__init__.py +0 -0
  69. {conductor_python-1.3.10/src/conductor/client/http → conductor_python-1.4.0/src/conductor/client/http/api}/__init__.py +0 -0
  70. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/application_resource_api.py +0 -0
  71. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/async_task_resource_api.py +0 -0
  72. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/authorization_resource_api.py +0 -0
  73. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/event_resource_api.py +0 -0
  74. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/gateway_auth_resource_api.py +0 -0
  75. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/group_resource_api.py +0 -0
  76. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/integration_resource_api.py +0 -0
  77. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/metadata_resource_api.py +0 -0
  78. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/prompt_resource_api.py +0 -0
  79. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/role_resource_api.py +0 -0
  80. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/scheduler_resource_api.py +0 -0
  81. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/schema_resource_api.py +0 -0
  82. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/secret_resource_api.py +0 -0
  83. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/service_registry_resource_api.py +0 -0
  84. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/task_resource_api.py +0 -0
  85. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/token_resource_api.py +0 -0
  86. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/user_resource_api.py +0 -0
  87. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/api/workflow_bulk_resource_api.py +0 -0
  88. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/__init__.py +0 -0
  89. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/action.py +0 -0
  90. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/auditable.py +0 -0
  91. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/authentication_config.py +0 -0
  92. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/authorization_request.py +0 -0
  93. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/bulk_response.py +0 -0
  94. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/circuit_breaker_transition_response.py +0 -0
  95. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/conductor_application.py +0 -0
  96. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/conductor_user.py +0 -0
  97. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/correlation_ids_search_request.py +0 -0
  98. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/create_or_update_application_request.py +0 -0
  99. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/create_or_update_role_request.py +0 -0
  100. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/event_handler.py +0 -0
  101. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/external_storage_location.py +0 -0
  102. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/generate_token_request.py +0 -0
  103. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/group.py +0 -0
  104. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/health.py +0 -0
  105. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/health_check_status.py +0 -0
  106. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration.py +0 -0
  107. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration_api.py +0 -0
  108. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration_api_update.py +0 -0
  109. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration_def.py +0 -0
  110. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/integration_update.py +0 -0
  111. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/permission.py +0 -0
  112. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/poll_data.py +0 -0
  113. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/prompt_template.py +0 -0
  114. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/prompt_test_request.py +0 -0
  115. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/proto_registry_entry.py +0 -0
  116. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/rate_limit.py +0 -0
  117. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/request_param.py +0 -0
  118. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/rerun_workflow_request.py +0 -0
  119. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/response.py +0 -0
  120. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/role.py +0 -0
  121. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/save_schedule_request.py +0 -0
  122. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/schema_def.py +0 -0
  123. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/scrollable_search_result_workflow_summary.py +0 -0
  124. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_task.py +0 -0
  125. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_task_summary.py +0 -0
  126. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_workflow.py +0 -0
  127. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_workflow_schedule_execution_model.py +0 -0
  128. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/search_result_workflow_summary.py +0 -0
  129. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/service_method.py +0 -0
  130. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/service_registry.py +0 -0
  131. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/signal_response.py +0 -0
  132. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/skip_task_request.py +0 -0
  133. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/start_workflow.py +0 -0
  134. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/start_workflow_request.py +0 -0
  135. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/state_change_event.py +0 -0
  136. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/sub_workflow_params.py +0 -0
  137. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/subject_ref.py +0 -0
  138. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/tag_object.py +0 -0
  139. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/tag_string.py +0 -0
  140. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/target_ref.py +0 -0
  141. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task.py +0 -0
  142. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_def.py +0 -0
  143. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_details.py +0 -0
  144. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_exec_log.py +0 -0
  145. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_result.py +0 -0
  146. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_result_status.py +0 -0
  147. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/task_summary.py +0 -0
  148. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/terminate_workflow.py +0 -0
  149. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/token.py +0 -0
  150. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/update_workflow_variables.py +0 -0
  151. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/upsert_group_request.py +0 -0
  152. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/upsert_user_request.py +0 -0
  153. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow.py +0 -0
  154. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_def.py +0 -0
  155. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_message.py +0 -0
  156. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_run.py +0 -0
  157. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_schedule.py +0 -0
  158. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_schedule_execution_model.py +0 -0
  159. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_state_update.py +0 -0
  160. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_status.py +0 -0
  161. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_summary.py +0 -0
  162. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_tag.py +0 -0
  163. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_task.py +0 -0
  164. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/models/workflow_test_request.py +0 -0
  165. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/http/thread.py +0 -0
  166. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/integration_client.py +0 -0
  167. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/metadata_client.py +0 -0
  168. {conductor_python-1.3.10/src/conductor/client/http/api → conductor_python-1.4.0/src/conductor/client/orkes}/__init__.py +0 -0
  169. {conductor_python-1.3.10/src/conductor/client/orkes → conductor_python-1.4.0/src/conductor/client/orkes/api}/__init__.py +0 -0
  170. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/api/tags_api.py +0 -0
  171. {conductor_python-1.3.10/src/conductor/client/orkes/api → conductor_python-1.4.0/src/conductor/client/orkes/models}/__init__.py +0 -0
  172. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/access_key.py +0 -0
  173. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/access_key_status.py +0 -0
  174. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/access_type.py +0 -0
  175. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/created_access_key.py +0 -0
  176. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/granted_permission.py +0 -0
  177. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/metadata_tag.py +0 -0
  178. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/models/ratelimit_tag.py +0 -0
  179. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_authorization_client.py +0 -0
  180. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_integration_client.py +0 -0
  181. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_metadata_client.py +0 -0
  182. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_prompt_client.py +0 -0
  183. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_scheduler_client.py +0 -0
  184. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_schema_client.py +0 -0
  185. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_secret_client.py +0 -0
  186. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_service_registry_client.py +0 -0
  187. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/orkes/orkes_task_client.py +0 -0
  188. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/prompt_client.py +0 -0
  189. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/scheduler_client.py +0 -0
  190. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/schema_client.py +0 -0
  191. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/secret_client.py +0 -0
  192. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/service_registry_client.py +0 -0
  193. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/task_client.py +0 -0
  194. {conductor_python-1.3.10/src/conductor/client/orkes/models → conductor_python-1.4.0/src/conductor/client/telemetry}/__init__.py +0 -0
  195. {conductor_python-1.3.10/src/conductor/client/telemetry → conductor_python-1.4.0/src/conductor/client/telemetry/model}/__init__.py +0 -0
  196. {conductor_python-1.3.10/src/conductor/client/telemetry/model → conductor_python-1.4.0/src/conductor/client/worker}/__init__.py +0 -0
  197. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/exception.py +0 -0
  198. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker_interface.py +0 -0
  199. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/worker/worker_loader.py +0 -0
  200. {conductor_python-1.3.10/src/conductor/client/worker → conductor_python-1.4.0/src/conductor/client/workflow}/__init__.py +0 -0
  201. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/conductor_workflow.py +0 -0
  202. {conductor_python-1.3.10/src/conductor/client/workflow → conductor_python-1.4.0/src/conductor/client/workflow/executor}/__init__.py +0 -0
  203. {conductor_python-1.3.10/src/conductor/client/workflow/executor → conductor_python-1.4.0/src/conductor/client/workflow/task}/__init__.py +0 -0
  204. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/do_while_task.py +0 -0
  205. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/dynamic_fork_task.py +0 -0
  206. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/dynamic_task.py +0 -0
  207. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/event_task.py +0 -0
  208. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/fork_task.py +0 -0
  209. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/get_document.py +0 -0
  210. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/http_poll_task.py +0 -0
  211. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/http_task.py +0 -0
  212. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/human_task.py +0 -0
  213. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/inline.py +0 -0
  214. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/javascript_task.py +0 -0
  215. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/join_task.py +0 -0
  216. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/json_jq_task.py +0 -0
  217. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/kafka_publish.py +0 -0
  218. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/kafka_publish_input.py +0 -0
  219. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/__init__.py +0 -0
  220. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/call_mcp_tool.py +0 -0
  221. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/chat_message.py +0 -0
  222. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/generate_audio.py +0 -0
  223. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/generate_image.py +0 -0
  224. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/list_mcp_tools.py +0 -0
  225. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_chat_complete.py +0 -0
  226. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_generate_embeddings.py +0 -0
  227. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_index_documents.py +0 -0
  228. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_index_text.py +0 -0
  229. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_query_embeddings.py +0 -0
  230. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_search_embeddings.py +0 -0
  231. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_search_index.py +0 -0
  232. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_store_embeddings.py +0 -0
  233. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/llm_text_complete.py +0 -0
  234. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/tool_call.py +0 -0
  235. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/tool_spec.py +0 -0
  236. {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
  237. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/utils/embedding_model.py +0 -0
  238. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/llm_tasks/utils/prompt.py +0 -0
  239. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/pull_workflow_messages_task.py +0 -0
  240. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/set_variable_task.py +0 -0
  241. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/simple_task.py +0 -0
  242. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/start_workflow_task.py +0 -0
  243. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/sub_workflow_task.py +0 -0
  244. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/switch_task.py +0 -0
  245. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/task.py +0 -0
  246. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/task_type.py +0 -0
  247. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/terminate_task.py +0 -0
  248. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/timeout_policy.py +0 -0
  249. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/wait_for_webhook_task.py +0 -0
  250. {conductor_python-1.3.10 → conductor_python-1.4.0}/src/conductor/client/workflow/task/wait_task.py +0 -0
  251. {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.10
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.9
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.31.0)
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 = OrkesClients(configuration=config)
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 details on all tracked metrics.
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 OrkesClients
369
+ from conductor.client.orkes_clients import ConductorClients
345
370
 
346
371
  config = Configuration()
347
- clients = OrkesClients(configuration=config)
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 = OrkesClients(configuration=config)
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 details on all tracked metrics.
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 OrkesClients
334
+ from conductor.client.orkes_clients import ConductorClients
310
335
 
311
336
  config = Configuration()
312
- clients = OrkesClients(configuration=config)
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.3.10" # Do not change! Placeholder. Real version injected during build (edited)
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.9"
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.31.0"
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 = "^8.4.1"
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 = "py39"
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.metrics_collector import MetricsCollector
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 = MetricsCollector(
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 hasattr(self.worker, 'execute_function'):
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).