conductor_ruby 0.1.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +142 -0
- data/LICENSE +190 -0
- data/README.md +517 -0
- data/examples/agentic_workflows/llm_chat.rb +106 -0
- data/examples/dynamic_workflow.rb +177 -0
- data/examples/event_handler.rb +94 -0
- data/examples/event_listener_examples.rb +430 -0
- data/examples/helloworld/greetings_worker.rb +24 -0
- data/examples/helloworld/helloworld.rb +99 -0
- data/examples/kitchensink.rb +213 -0
- data/examples/metadata_journey.rb +189 -0
- data/examples/metrics_example.rb +284 -0
- data/examples/new_dsl_demo.rb +141 -0
- data/examples/orkes/http_poll.rb +83 -0
- data/examples/orkes/secrets_example.rb +69 -0
- data/examples/orkes/wait_for_webhook.rb +90 -0
- data/examples/prompt_journey.rb +245 -0
- data/examples/rag_workflow.rb +167 -0
- data/examples/schedule_journey.rb +244 -0
- data/examples/simple_worker.rb +125 -0
- data/examples/simple_workflow.rb +89 -0
- data/examples/task_context_example.rb +257 -0
- data/examples/task_listener_example.rb +192 -0
- data/examples/worker_configuration_example.rb +282 -0
- data/examples/workflow_dsl.rb +316 -0
- data/examples/workflow_ops.rb +305 -0
- data/lib/conductor/client/authorization_client.rb +238 -0
- data/lib/conductor/client/integration_client.rb +108 -0
- data/lib/conductor/client/metadata_client.rb +139 -0
- data/lib/conductor/client/prompt_client.rb +58 -0
- data/lib/conductor/client/scheduler_client.rb +132 -0
- data/lib/conductor/client/schema_client.rb +32 -0
- data/lib/conductor/client/secret_client.rb +48 -0
- data/lib/conductor/client/task_client.rb +168 -0
- data/lib/conductor/client/workflow_client.rb +242 -0
- data/lib/conductor/configuration/authentication_settings.rb +17 -0
- data/lib/conductor/configuration.rb +103 -0
- data/lib/conductor/exceptions.rb +86 -0
- data/lib/conductor/http/api/application_resource_api.rb +107 -0
- data/lib/conductor/http/api/authorization_resource_api.rb +56 -0
- data/lib/conductor/http/api/event_resource_api.rb +133 -0
- data/lib/conductor/http/api/gateway_auth_resource_api.rb +48 -0
- data/lib/conductor/http/api/group_resource_api.rb +76 -0
- data/lib/conductor/http/api/integration_resource_api.rb +145 -0
- data/lib/conductor/http/api/metadata_resource_api.rb +231 -0
- data/lib/conductor/http/api/prompt_resource_api.rb +81 -0
- data/lib/conductor/http/api/role_resource_api.rb +60 -0
- data/lib/conductor/http/api/scheduler_resource_api.rb +211 -0
- data/lib/conductor/http/api/schema_resource_api.rb +82 -0
- data/lib/conductor/http/api/secret_resource_api.rb +134 -0
- data/lib/conductor/http/api/task_resource_api.rb +321 -0
- data/lib/conductor/http/api/token_resource_api.rb +42 -0
- data/lib/conductor/http/api/user_resource_api.rb +59 -0
- data/lib/conductor/http/api/workflow_bulk_resource_api.rb +91 -0
- data/lib/conductor/http/api/workflow_resource_api.rb +451 -0
- data/lib/conductor/http/api_client.rb +437 -0
- data/lib/conductor/http/models/authentication_config.rb +67 -0
- data/lib/conductor/http/models/authorization_request.rb +39 -0
- data/lib/conductor/http/models/base_model.rb +162 -0
- data/lib/conductor/http/models/bulk_response.rb +39 -0
- data/lib/conductor/http/models/conductor_application.rb +39 -0
- data/lib/conductor/http/models/conductor_user.rb +53 -0
- data/lib/conductor/http/models/create_or_update_application_request.rb +24 -0
- data/lib/conductor/http/models/create_or_update_role_request.rb +27 -0
- data/lib/conductor/http/models/event_handler.rb +130 -0
- data/lib/conductor/http/models/generate_token_request.rb +27 -0
- data/lib/conductor/http/models/group.rb +36 -0
- data/lib/conductor/http/models/integration.rb +70 -0
- data/lib/conductor/http/models/integration_api.rb +53 -0
- data/lib/conductor/http/models/integration_api_update.rb +43 -0
- data/lib/conductor/http/models/integration_update.rb +36 -0
- data/lib/conductor/http/models/permission.rb +24 -0
- data/lib/conductor/http/models/poll_data.rb +33 -0
- data/lib/conductor/http/models/prompt_template.rb +59 -0
- data/lib/conductor/http/models/prompt_template_test_request.rb +43 -0
- data/lib/conductor/http/models/rerun_workflow_request.rb +37 -0
- data/lib/conductor/http/models/role.rb +27 -0
- data/lib/conductor/http/models/schema_def.rb +59 -0
- data/lib/conductor/http/models/search_result.rb +187 -0
- data/lib/conductor/http/models/skip_task_request.rb +27 -0
- data/lib/conductor/http/models/start_workflow_request.rb +68 -0
- data/lib/conductor/http/models/subject_ref.rb +35 -0
- data/lib/conductor/http/models/tag_object.rb +36 -0
- data/lib/conductor/http/models/target_ref.rb +39 -0
- data/lib/conductor/http/models/task.rb +156 -0
- data/lib/conductor/http/models/task_def.rb +95 -0
- data/lib/conductor/http/models/task_exec_log.rb +30 -0
- data/lib/conductor/http/models/task_result.rb +115 -0
- data/lib/conductor/http/models/task_result_status.rb +24 -0
- data/lib/conductor/http/models/token.rb +33 -0
- data/lib/conductor/http/models/upsert_group_request.rb +30 -0
- data/lib/conductor/http/models/upsert_user_request.rb +39 -0
- data/lib/conductor/http/models/workflow.rb +202 -0
- data/lib/conductor/http/models/workflow_def.rb +73 -0
- data/lib/conductor/http/models/workflow_schedule.rb +100 -0
- data/lib/conductor/http/models/workflow_state_update.rb +30 -0
- data/lib/conductor/http/models/workflow_status_constants.rb +57 -0
- data/lib/conductor/http/models/workflow_task.rb +169 -0
- data/lib/conductor/http/models/workflow_test_request.rb +67 -0
- data/lib/conductor/http/rest_client.rb +211 -0
- data/lib/conductor/orkes/models/access_key.rb +56 -0
- data/lib/conductor/orkes/models/granted_permission.rb +27 -0
- data/lib/conductor/orkes/models/metadata_tag.rb +15 -0
- data/lib/conductor/orkes/models/rate_limit_tag.rb +15 -0
- data/lib/conductor/orkes/orkes_clients.rb +69 -0
- data/lib/conductor/version.rb +5 -0
- data/lib/conductor/worker/events/conductor_event.rb +40 -0
- data/lib/conductor/worker/events/global_dispatcher.rb +37 -0
- data/lib/conductor/worker/events/http_events.rb +25 -0
- data/lib/conductor/worker/events/listener_registry.rb +40 -0
- data/lib/conductor/worker/events/listeners.rb +34 -0
- data/lib/conductor/worker/events/sync_event_dispatcher.rb +78 -0
- data/lib/conductor/worker/events/task_runner_events.rb +271 -0
- data/lib/conductor/worker/events/workflow_events.rb +49 -0
- data/lib/conductor/worker/fiber_executor.rb +532 -0
- data/lib/conductor/worker/ractor_task_runner.rb +501 -0
- data/lib/conductor/worker/task_context.rb +114 -0
- data/lib/conductor/worker/task_definition_registrar.rb +322 -0
- data/lib/conductor/worker/task_handler.rb +360 -0
- data/lib/conductor/worker/task_in_progress.rb +60 -0
- data/lib/conductor/worker/task_runner.rb +538 -0
- data/lib/conductor/worker/telemetry/metrics_collector.rb +196 -0
- data/lib/conductor/worker/telemetry/prometheus_backend.rb +224 -0
- data/lib/conductor/worker/worker.rb +355 -0
- data/lib/conductor/worker/worker_config.rb +154 -0
- data/lib/conductor/worker/worker_registry.rb +71 -0
- data/lib/conductor/workflow/dsl/input_ref.rb +37 -0
- data/lib/conductor/workflow/dsl/output_ref.rb +44 -0
- data/lib/conductor/workflow/dsl/parallel_builder.rb +49 -0
- data/lib/conductor/workflow/dsl/switch_builder.rb +74 -0
- data/lib/conductor/workflow/dsl/task_ref.rb +178 -0
- data/lib/conductor/workflow/dsl/workflow_builder.rb +1016 -0
- data/lib/conductor/workflow/dsl/workflow_definition.rb +150 -0
- data/lib/conductor/workflow/llm/chat_message.rb +47 -0
- data/lib/conductor/workflow/llm/embedding_model.rb +19 -0
- data/lib/conductor/workflow/llm/tool_call.rb +43 -0
- data/lib/conductor/workflow/llm/tool_spec.rb +46 -0
- data/lib/conductor/workflow/task_type.rb +68 -0
- data/lib/conductor/workflow/timeout_policy.rb +31 -0
- data/lib/conductor/workflow/workflow_executor.rb +373 -0
- data/lib/conductor.rb +192 -0
- metadata +359 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conductor
|
|
4
|
+
module Http
|
|
5
|
+
module Models
|
|
6
|
+
# Request to test a workflow with mocked task outputs
|
|
7
|
+
class WorkflowTestRequest < BaseModel
|
|
8
|
+
SWAGGER_TYPES = {
|
|
9
|
+
workflow_def: 'WorkflowDef',
|
|
10
|
+
name: 'String',
|
|
11
|
+
version: 'Integer',
|
|
12
|
+
input: 'Hash<String, Object>',
|
|
13
|
+
correlation_id: 'String',
|
|
14
|
+
task_ref_to_mock_output: 'Hash<String, Array<WorkflowTestTaskResult>>',
|
|
15
|
+
external_input_payload_storage_path: 'String',
|
|
16
|
+
sub_workflow_test_request: 'Hash<String, WorkflowTestRequest>'
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
ATTRIBUTE_MAP = {
|
|
20
|
+
workflow_def: :workflowDef,
|
|
21
|
+
name: :name,
|
|
22
|
+
version: :version,
|
|
23
|
+
input: :input,
|
|
24
|
+
correlation_id: :correlationId,
|
|
25
|
+
task_ref_to_mock_output: :taskRefToMockOutput,
|
|
26
|
+
external_input_payload_storage_path: :externalInputPayloadStoragePath,
|
|
27
|
+
sub_workflow_test_request: :subWorkflowTestRequest
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
attr_accessor :workflow_def, :name, :version, :input, :correlation_id,
|
|
31
|
+
:task_ref_to_mock_output, :external_input_payload_storage_path,
|
|
32
|
+
:sub_workflow_test_request
|
|
33
|
+
|
|
34
|
+
def initialize(params = {})
|
|
35
|
+
@workflow_def = params[:workflow_def]
|
|
36
|
+
@name = params[:name]
|
|
37
|
+
@version = params[:version]
|
|
38
|
+
@input = params[:input] || {}
|
|
39
|
+
@correlation_id = params[:correlation_id]
|
|
40
|
+
@task_ref_to_mock_output = params[:task_ref_to_mock_output] || {}
|
|
41
|
+
@external_input_payload_storage_path = params[:external_input_payload_storage_path]
|
|
42
|
+
@sub_workflow_test_request = params[:sub_workflow_test_request] || {}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Mock task result for workflow testing
|
|
47
|
+
class WorkflowTestTaskResult < BaseModel
|
|
48
|
+
SWAGGER_TYPES = {
|
|
49
|
+
status: 'String',
|
|
50
|
+
output: 'Hash<String, Object>'
|
|
51
|
+
}.freeze
|
|
52
|
+
|
|
53
|
+
ATTRIBUTE_MAP = {
|
|
54
|
+
status: :status,
|
|
55
|
+
output: :output
|
|
56
|
+
}.freeze
|
|
57
|
+
|
|
58
|
+
attr_accessor :status, :output
|
|
59
|
+
|
|
60
|
+
def initialize(params = {})
|
|
61
|
+
@status = params[:status] || 'COMPLETED'
|
|
62
|
+
@output = params[:output] || {}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'faraday'
|
|
4
|
+
require 'faraday/net_http_persistent'
|
|
5
|
+
require 'faraday/retry'
|
|
6
|
+
require 'json'
|
|
7
|
+
require 'logger'
|
|
8
|
+
require 'uri'
|
|
9
|
+
|
|
10
|
+
module Conductor
|
|
11
|
+
module Http
|
|
12
|
+
# Faraday-based REST client with HTTP/2 support
|
|
13
|
+
class RestClient
|
|
14
|
+
attr_reader :connection
|
|
15
|
+
|
|
16
|
+
def initialize(configuration = nil, logger: nil)
|
|
17
|
+
@configuration = configuration
|
|
18
|
+
@logger = logger || Logger.new(File::NULL)
|
|
19
|
+
@connection = build_connection
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Main request method
|
|
23
|
+
def request(method, url, query: nil, headers: nil, body: nil, metric_uri: nil)
|
|
24
|
+
method = method.to_s.upcase
|
|
25
|
+
raise ArgumentError, "Invalid HTTP method: #{method}" unless valid_method?(method)
|
|
26
|
+
|
|
27
|
+
headers ||= {}
|
|
28
|
+
headers['Content-Type'] ||= 'application/json' if %w[POST PUT PATCH DELETE OPTIONS].include?(method)
|
|
29
|
+
|
|
30
|
+
timing = http_metrics_enabled?
|
|
31
|
+
start_time = Time.now if timing
|
|
32
|
+
status_code = '0'
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
response = @connection.run_request(method.downcase.to_sym, url, nil, headers) do |req|
|
|
36
|
+
req.params = query if query
|
|
37
|
+
req.body = serialize_body(body, headers['Content-Type']) if body
|
|
38
|
+
end
|
|
39
|
+
status_code = response.status.to_s
|
|
40
|
+
|
|
41
|
+
result = handle_response(response)
|
|
42
|
+
emit_http_event(method, url, status_code, start_time, metric_uri: metric_uri) if timing
|
|
43
|
+
result
|
|
44
|
+
rescue Faraday::TimeoutError => e
|
|
45
|
+
emit_http_event(method, url, '0', start_time, metric_uri: metric_uri) if timing
|
|
46
|
+
raise ApiError.new("Request timeout: #{e.message}", status: 0, reason: 'Timeout')
|
|
47
|
+
rescue Faraday::ConnectionFailed => e
|
|
48
|
+
emit_http_event(method, url, '0', start_time, metric_uri: metric_uri) if timing
|
|
49
|
+
raise ApiError.new("Connection error: #{e.message}", status: 0, reason: 'ConnectionFailed')
|
|
50
|
+
rescue ApiError, AuthorizationError
|
|
51
|
+
emit_http_event(method, url, status_code, start_time, metric_uri: metric_uri) if timing
|
|
52
|
+
raise
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Convenience methods
|
|
57
|
+
def get(url, query: nil, headers: nil)
|
|
58
|
+
request('GET', url, query: query, headers: headers)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def post(url, body: nil, query: nil, headers: nil)
|
|
62
|
+
request('POST', url, query: query, headers: headers, body: body)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def put(url, body: nil, query: nil, headers: nil)
|
|
66
|
+
request('PUT', url, query: query, headers: headers, body: body)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def patch(url, body: nil, query: nil, headers: nil)
|
|
70
|
+
request('PATCH', url, query: query, headers: headers, body: body)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def delete(url, body: nil, query: nil, headers: nil)
|
|
74
|
+
request('DELETE', url, query: query, headers: headers, body: body)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def head(url, query: nil, headers: nil)
|
|
78
|
+
request('HEAD', url, query: query, headers: headers)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def options(url, body: nil, query: nil, headers: nil)
|
|
82
|
+
request('OPTIONS', url, query: query, headers: headers, body: body)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def close
|
|
86
|
+
@connection&.close
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def http_metrics_enabled?
|
|
92
|
+
defined?(Conductor::Worker::Events::GlobalDispatcher) &&
|
|
93
|
+
Conductor::Worker::Events::GlobalDispatcher.http_metrics_enabled?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def emit_http_event(method, url, status, start_time, metric_uri: nil)
|
|
97
|
+
duration_ms = (Time.now - start_time) * 1000
|
|
98
|
+
uri_path = metric_uri || URI.parse(url).request_uri
|
|
99
|
+
event = Conductor::Worker::Events::HttpApiRequest.new(
|
|
100
|
+
method: method, uri: uri_path, status: status, duration_ms: duration_ms
|
|
101
|
+
)
|
|
102
|
+
Conductor::Worker::Events::GlobalDispatcher.publish(event)
|
|
103
|
+
rescue StandardError => e
|
|
104
|
+
@logger.debug { "Telemetry error (non-fatal): #{e.class}: #{e.message}" }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def build_connection
|
|
108
|
+
Faraday.new do |conn|
|
|
109
|
+
# HTTP/2 adapter with persistent connections
|
|
110
|
+
conn.adapter :net_http_persistent do |http|
|
|
111
|
+
http.idle_timeout = 30
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Retry middleware (3 retries with exponential backoff)
|
|
115
|
+
conn.request :retry,
|
|
116
|
+
max: 3,
|
|
117
|
+
interval: 0.5,
|
|
118
|
+
backoff_factor: 2,
|
|
119
|
+
retry_statuses: [408, 429, 500, 502, 503, 504],
|
|
120
|
+
methods: %i[get post put patch delete]
|
|
121
|
+
|
|
122
|
+
# Connection settings
|
|
123
|
+
conn.options.timeout = 120 # 120s total timeout
|
|
124
|
+
conn.options.open_timeout = 10 # 10s connection timeout
|
|
125
|
+
|
|
126
|
+
# SSL settings from configuration
|
|
127
|
+
if @configuration
|
|
128
|
+
conn.ssl.verify = @configuration.verify_ssl
|
|
129
|
+
conn.ssl.ca_file = @configuration.ssl_ca_cert if @configuration.ssl_ca_cert
|
|
130
|
+
conn.ssl.client_cert = @configuration.cert_file if @configuration.cert_file
|
|
131
|
+
conn.ssl.client_key = @configuration.key_file if @configuration.key_file
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Proxy settings
|
|
135
|
+
conn.proxy = @configuration.proxy if @configuration&.proxy
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def valid_method?(method)
|
|
140
|
+
%w[GET HEAD DELETE POST PUT PATCH OPTIONS].include?(method)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def serialize_body(body, content_type)
|
|
144
|
+
return body if body.is_a?(String)
|
|
145
|
+
|
|
146
|
+
if content_type&.include?('json')
|
|
147
|
+
body.is_a?(Hash) || body.is_a?(Array) ? JSON.generate(body) : body.to_s
|
|
148
|
+
else
|
|
149
|
+
body
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def handle_response(response)
|
|
154
|
+
# Check for auth errors first (401/403)
|
|
155
|
+
if [401, 403].include?(response.status)
|
|
156
|
+
raise AuthorizationError.new(
|
|
157
|
+
"Authorization failed: #{response.status}",
|
|
158
|
+
status: response.status,
|
|
159
|
+
body: response.body,
|
|
160
|
+
headers: response.headers.to_h
|
|
161
|
+
)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Check for other non-2xx responses
|
|
165
|
+
unless (200..299).cover?(response.status)
|
|
166
|
+
error_message = parse_error_message(response)
|
|
167
|
+
raise ApiError.new(
|
|
168
|
+
error_message,
|
|
169
|
+
status: response.status,
|
|
170
|
+
code: response.status,
|
|
171
|
+
reason: response.reason_phrase,
|
|
172
|
+
body: response.body,
|
|
173
|
+
headers: response.headers.to_h
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Return successful response
|
|
178
|
+
RestResponse.new(response)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def parse_error_message(response)
|
|
182
|
+
# Try to parse JSON error message
|
|
183
|
+
data = begin
|
|
184
|
+
JSON.parse(response.body)
|
|
185
|
+
rescue StandardError
|
|
186
|
+
nil
|
|
187
|
+
end
|
|
188
|
+
message = data&.dig('message') || response.reason_phrase || "HTTP #{response.status}"
|
|
189
|
+
"(#{response.status}) #{message}"
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Wrapper for Faraday response
|
|
194
|
+
class RestResponse
|
|
195
|
+
attr_reader :status, :reason, :body, :headers
|
|
196
|
+
|
|
197
|
+
def initialize(faraday_response)
|
|
198
|
+
@status = faraday_response.status
|
|
199
|
+
@reason = faraday_response.reason_phrase
|
|
200
|
+
@body = faraday_response.body
|
|
201
|
+
@headers = faraday_response.headers.to_h
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def json
|
|
205
|
+
@json ||= JSON.parse(@body) if @body && !@body.empty?
|
|
206
|
+
rescue JSON::ParserError
|
|
207
|
+
nil
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conductor
|
|
4
|
+
module Orkes
|
|
5
|
+
module Models
|
|
6
|
+
# AccessKeyStatus constants
|
|
7
|
+
module AccessKeyStatus
|
|
8
|
+
ACTIVE = 'ACTIVE'
|
|
9
|
+
INACTIVE = 'INACTIVE'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# AccessKey model - represents an application access key
|
|
13
|
+
class AccessKey < Conductor::Http::Models::BaseModel
|
|
14
|
+
SWAGGER_TYPES = {
|
|
15
|
+
id: 'String',
|
|
16
|
+
status: 'String',
|
|
17
|
+
created_at: 'Integer'
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
ATTRIBUTE_MAP = {
|
|
21
|
+
id: :id,
|
|
22
|
+
status: :status,
|
|
23
|
+
created_at: :createdAt
|
|
24
|
+
}.freeze
|
|
25
|
+
|
|
26
|
+
attr_accessor :id, :status, :created_at
|
|
27
|
+
|
|
28
|
+
def initialize(params = {})
|
|
29
|
+
@id = params[:id]
|
|
30
|
+
@status = params[:status] || AccessKeyStatus::ACTIVE
|
|
31
|
+
@created_at = params[:created_at]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# CreatedAccessKey model - returned when creating a new access key
|
|
36
|
+
class CreatedAccessKey < Conductor::Http::Models::BaseModel
|
|
37
|
+
SWAGGER_TYPES = {
|
|
38
|
+
id: 'String',
|
|
39
|
+
secret: 'String'
|
|
40
|
+
}.freeze
|
|
41
|
+
|
|
42
|
+
ATTRIBUTE_MAP = {
|
|
43
|
+
id: :id,
|
|
44
|
+
secret: :secret
|
|
45
|
+
}.freeze
|
|
46
|
+
|
|
47
|
+
attr_accessor :id, :secret
|
|
48
|
+
|
|
49
|
+
def initialize(params = {})
|
|
50
|
+
@id = params[:id]
|
|
51
|
+
@secret = params[:secret]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conductor
|
|
4
|
+
module Orkes
|
|
5
|
+
module Models
|
|
6
|
+
# GrantedPermission model - represents a permission granted on a target
|
|
7
|
+
class GrantedPermission < Conductor::Http::Models::BaseModel
|
|
8
|
+
SWAGGER_TYPES = {
|
|
9
|
+
target: 'TargetRef',
|
|
10
|
+
access: 'Array<String>'
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
ATTRIBUTE_MAP = {
|
|
14
|
+
target: :target,
|
|
15
|
+
access: :access
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
attr_accessor :target, :access
|
|
19
|
+
|
|
20
|
+
def initialize(params = {})
|
|
21
|
+
@target = params[:target]
|
|
22
|
+
@access = params[:access]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conductor
|
|
4
|
+
module Orkes
|
|
5
|
+
module Models
|
|
6
|
+
# MetadataTag - a tag with type METADATA
|
|
7
|
+
# Convenience subclass of TagObject that sets type to METADATA
|
|
8
|
+
class MetadataTag < Conductor::Http::Models::TagObject
|
|
9
|
+
def initialize(key:, value:)
|
|
10
|
+
super(key: key, type: Conductor::Http::Models::TagType::METADATA, value: value)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conductor
|
|
4
|
+
module Orkes
|
|
5
|
+
module Models
|
|
6
|
+
# RateLimitTag - a tag with type RATE_LIMIT
|
|
7
|
+
# Convenience subclass of TagObject that sets type to RATE_LIMIT
|
|
8
|
+
class RateLimitTag < Conductor::Http::Models::TagObject
|
|
9
|
+
def initialize(key:, value:)
|
|
10
|
+
super(key: key, type: Conductor::Http::Models::TagType::RATE_LIMIT, value: value)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conductor
|
|
4
|
+
module Orkes
|
|
5
|
+
# OrkesClients - Factory class that creates all high-level clients from a single configuration
|
|
6
|
+
# This is the primary entry point for Orkes Conductor users.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# config = Conductor::Configuration.new
|
|
10
|
+
# config.server_url = 'https://developer.orkescloud.com/api'
|
|
11
|
+
# config.authentication_settings = Conductor::Configuration::AuthenticationSettings.new(
|
|
12
|
+
# key_id: 'your_key', key_secret: 'your_secret'
|
|
13
|
+
# )
|
|
14
|
+
# clients = Conductor::Orkes::OrkesClients.new(config)
|
|
15
|
+
#
|
|
16
|
+
# workflow_client = clients.get_workflow_client
|
|
17
|
+
# task_client = clients.get_task_client
|
|
18
|
+
# secret_client = clients.get_secret_client
|
|
19
|
+
#
|
|
20
|
+
class OrkesClients
|
|
21
|
+
attr_reader :configuration, :api_client
|
|
22
|
+
|
|
23
|
+
def initialize(configuration = nil)
|
|
24
|
+
@configuration = configuration || Configuration.new
|
|
25
|
+
@api_client = Http::ApiClient.new(configuration: @configuration)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def get_workflow_client
|
|
29
|
+
Client::WorkflowClient.new(@configuration)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def get_task_client
|
|
33
|
+
Client::TaskClient.new(@configuration)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def get_metadata_client
|
|
37
|
+
Client::MetadataClient.new(@configuration)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def get_scheduler_client
|
|
41
|
+
Client::SchedulerClient.new(@configuration)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def get_authorization_client
|
|
45
|
+
Client::AuthorizationClient.new(@api_client)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def get_secret_client
|
|
49
|
+
Client::SecretClient.new(@api_client)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def get_integration_client
|
|
53
|
+
Client::IntegrationClient.new(@api_client)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def get_prompt_client
|
|
57
|
+
Client::PromptClient.new(@api_client)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def get_schema_client
|
|
61
|
+
Client::SchemaClient.new(@api_client)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def get_workflow_executor
|
|
65
|
+
Workflow::WorkflowExecutor.new(@configuration)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conductor
|
|
4
|
+
module Worker
|
|
5
|
+
module Events
|
|
6
|
+
# Base class for all Conductor events
|
|
7
|
+
# Provides a timestamp for when the event occurred
|
|
8
|
+
class ConductorEvent
|
|
9
|
+
# @return [Time] UTC timestamp when event was created
|
|
10
|
+
attr_reader :timestamp
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@timestamp = Time.now.utc
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [Hash] Event as a hash for serialization
|
|
17
|
+
def to_h
|
|
18
|
+
{ timestamp: @timestamp.iso8601(3) }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Base class for task runner events
|
|
23
|
+
# All events related to task polling and execution inherit from this
|
|
24
|
+
class TaskRunnerEvent < ConductorEvent
|
|
25
|
+
# @return [String] The task type/definition name
|
|
26
|
+
attr_reader :task_type
|
|
27
|
+
|
|
28
|
+
# @param task_type [String] Task definition name
|
|
29
|
+
def initialize(task_type:)
|
|
30
|
+
super()
|
|
31
|
+
@task_type = task_type
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_h
|
|
35
|
+
super.merge(task_type: @task_type)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'sync_event_dispatcher'
|
|
4
|
+
|
|
5
|
+
module Conductor
|
|
6
|
+
module Worker
|
|
7
|
+
module Events
|
|
8
|
+
# Process-wide default event dispatcher.
|
|
9
|
+
#
|
|
10
|
+
# Used by library layers (e.g. HTTP client) that don't have an obvious
|
|
11
|
+
# owner to receive a dispatcher reference. Listeners can subscribe to this
|
|
12
|
+
# singleton to receive events regardless of which RestClient/ApiClient
|
|
13
|
+
# instance generated them.
|
|
14
|
+
class GlobalDispatcher
|
|
15
|
+
class << self
|
|
16
|
+
def instance
|
|
17
|
+
@instance ||= SyncEventDispatcher.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def reset!
|
|
21
|
+
@instance = SyncEventDispatcher.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def publish(event)
|
|
25
|
+
instance.publish(event)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def http_metrics_enabled?
|
|
29
|
+
instance.has_listeners?(HttpApiRequest)
|
|
30
|
+
rescue StandardError
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'conductor_event'
|
|
4
|
+
|
|
5
|
+
module Conductor
|
|
6
|
+
module Worker
|
|
7
|
+
module Events
|
|
8
|
+
class HttpApiRequest < ConductorEvent
|
|
9
|
+
attr_reader :method, :uri, :status, :duration_ms
|
|
10
|
+
|
|
11
|
+
def initialize(method:, uri:, status:, duration_ms:)
|
|
12
|
+
super()
|
|
13
|
+
@method = method.to_s.upcase
|
|
14
|
+
@uri = uri.to_s
|
|
15
|
+
@status = status.to_s
|
|
16
|
+
@duration_ms = duration_ms
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_h
|
|
20
|
+
super.merge(method: @method, uri: @uri, status: @status, duration_ms: @duration_ms)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'task_runner_events'
|
|
4
|
+
require_relative 'workflow_events'
|
|
5
|
+
require_relative 'http_events'
|
|
6
|
+
|
|
7
|
+
module Conductor
|
|
8
|
+
module Worker
|
|
9
|
+
module Events
|
|
10
|
+
class ListenerRegistry
|
|
11
|
+
EVENT_METHOD_MAP = {
|
|
12
|
+
PollStarted => :on_poll_started,
|
|
13
|
+
PollCompleted => :on_poll_completed,
|
|
14
|
+
PollFailure => :on_poll_failure,
|
|
15
|
+
TaskExecutionStarted => :on_task_execution_started,
|
|
16
|
+
TaskExecutionCompleted => :on_task_execution_completed,
|
|
17
|
+
TaskExecutionFailure => :on_task_execution_failure,
|
|
18
|
+
TaskUpdateCompleted => :on_task_update_completed,
|
|
19
|
+
TaskUpdateFailure => :on_task_update_failure,
|
|
20
|
+
TaskPaused => :on_task_paused,
|
|
21
|
+
ThreadUncaughtException => :on_thread_uncaught_exception,
|
|
22
|
+
ActiveWorkersChanged => :on_active_workers_changed,
|
|
23
|
+
WorkflowStartError => :on_workflow_start_error,
|
|
24
|
+
WorkflowInputSize => :on_workflow_input_size,
|
|
25
|
+
HttpApiRequest => :on_http_api_request
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
def self.register_task_runner_listener(listener, dispatcher)
|
|
29
|
+
EVENT_METHOD_MAP.each do |event_class, method_name|
|
|
30
|
+
dispatcher.register(event_class, ->(event) { listener.send(method_name, event) }) if listener.respond_to?(method_name)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.register_all(listeners, dispatcher)
|
|
35
|
+
listeners.each { |listener| register_task_runner_listener(listener, dispatcher) }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conductor
|
|
4
|
+
module Worker
|
|
5
|
+
module Events
|
|
6
|
+
# Listener protocol for task runner events.
|
|
7
|
+
# All methods are optional - the dispatcher uses duck typing (respond_to?).
|
|
8
|
+
module TaskRunnerEventsListener
|
|
9
|
+
def on_poll_started(event); end
|
|
10
|
+
def on_poll_completed(event); end
|
|
11
|
+
def on_poll_failure(event); end
|
|
12
|
+
def on_task_execution_started(event); end
|
|
13
|
+
def on_task_execution_completed(event); end
|
|
14
|
+
def on_task_execution_failure(event); end
|
|
15
|
+
def on_task_update_completed(event); end
|
|
16
|
+
def on_task_update_failure(event); end
|
|
17
|
+
def on_task_paused(event); end
|
|
18
|
+
def on_thread_uncaught_exception(event); end
|
|
19
|
+
def on_active_workers_changed(event); end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Listener protocol for workflow-lifecycle events
|
|
23
|
+
module WorkflowEventsListener
|
|
24
|
+
def on_workflow_start_error(event); end
|
|
25
|
+
def on_workflow_input_size(event); end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Listener protocol for HTTP API client events
|
|
29
|
+
module HttpEventsListener
|
|
30
|
+
def on_http_api_request(event); end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|