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.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +142 -0
  3. data/LICENSE +190 -0
  4. data/README.md +517 -0
  5. data/examples/agentic_workflows/llm_chat.rb +106 -0
  6. data/examples/dynamic_workflow.rb +177 -0
  7. data/examples/event_handler.rb +94 -0
  8. data/examples/event_listener_examples.rb +430 -0
  9. data/examples/helloworld/greetings_worker.rb +24 -0
  10. data/examples/helloworld/helloworld.rb +99 -0
  11. data/examples/kitchensink.rb +213 -0
  12. data/examples/metadata_journey.rb +189 -0
  13. data/examples/metrics_example.rb +284 -0
  14. data/examples/new_dsl_demo.rb +141 -0
  15. data/examples/orkes/http_poll.rb +83 -0
  16. data/examples/orkes/secrets_example.rb +69 -0
  17. data/examples/orkes/wait_for_webhook.rb +90 -0
  18. data/examples/prompt_journey.rb +245 -0
  19. data/examples/rag_workflow.rb +167 -0
  20. data/examples/schedule_journey.rb +244 -0
  21. data/examples/simple_worker.rb +125 -0
  22. data/examples/simple_workflow.rb +89 -0
  23. data/examples/task_context_example.rb +257 -0
  24. data/examples/task_listener_example.rb +192 -0
  25. data/examples/worker_configuration_example.rb +282 -0
  26. data/examples/workflow_dsl.rb +316 -0
  27. data/examples/workflow_ops.rb +305 -0
  28. data/lib/conductor/client/authorization_client.rb +238 -0
  29. data/lib/conductor/client/integration_client.rb +108 -0
  30. data/lib/conductor/client/metadata_client.rb +139 -0
  31. data/lib/conductor/client/prompt_client.rb +58 -0
  32. data/lib/conductor/client/scheduler_client.rb +132 -0
  33. data/lib/conductor/client/schema_client.rb +32 -0
  34. data/lib/conductor/client/secret_client.rb +48 -0
  35. data/lib/conductor/client/task_client.rb +168 -0
  36. data/lib/conductor/client/workflow_client.rb +242 -0
  37. data/lib/conductor/configuration/authentication_settings.rb +17 -0
  38. data/lib/conductor/configuration.rb +103 -0
  39. data/lib/conductor/exceptions.rb +86 -0
  40. data/lib/conductor/http/api/application_resource_api.rb +107 -0
  41. data/lib/conductor/http/api/authorization_resource_api.rb +56 -0
  42. data/lib/conductor/http/api/event_resource_api.rb +133 -0
  43. data/lib/conductor/http/api/gateway_auth_resource_api.rb +48 -0
  44. data/lib/conductor/http/api/group_resource_api.rb +76 -0
  45. data/lib/conductor/http/api/integration_resource_api.rb +145 -0
  46. data/lib/conductor/http/api/metadata_resource_api.rb +231 -0
  47. data/lib/conductor/http/api/prompt_resource_api.rb +81 -0
  48. data/lib/conductor/http/api/role_resource_api.rb +60 -0
  49. data/lib/conductor/http/api/scheduler_resource_api.rb +211 -0
  50. data/lib/conductor/http/api/schema_resource_api.rb +82 -0
  51. data/lib/conductor/http/api/secret_resource_api.rb +134 -0
  52. data/lib/conductor/http/api/task_resource_api.rb +321 -0
  53. data/lib/conductor/http/api/token_resource_api.rb +42 -0
  54. data/lib/conductor/http/api/user_resource_api.rb +59 -0
  55. data/lib/conductor/http/api/workflow_bulk_resource_api.rb +91 -0
  56. data/lib/conductor/http/api/workflow_resource_api.rb +451 -0
  57. data/lib/conductor/http/api_client.rb +437 -0
  58. data/lib/conductor/http/models/authentication_config.rb +67 -0
  59. data/lib/conductor/http/models/authorization_request.rb +39 -0
  60. data/lib/conductor/http/models/base_model.rb +162 -0
  61. data/lib/conductor/http/models/bulk_response.rb +39 -0
  62. data/lib/conductor/http/models/conductor_application.rb +39 -0
  63. data/lib/conductor/http/models/conductor_user.rb +53 -0
  64. data/lib/conductor/http/models/create_or_update_application_request.rb +24 -0
  65. data/lib/conductor/http/models/create_or_update_role_request.rb +27 -0
  66. data/lib/conductor/http/models/event_handler.rb +130 -0
  67. data/lib/conductor/http/models/generate_token_request.rb +27 -0
  68. data/lib/conductor/http/models/group.rb +36 -0
  69. data/lib/conductor/http/models/integration.rb +70 -0
  70. data/lib/conductor/http/models/integration_api.rb +53 -0
  71. data/lib/conductor/http/models/integration_api_update.rb +43 -0
  72. data/lib/conductor/http/models/integration_update.rb +36 -0
  73. data/lib/conductor/http/models/permission.rb +24 -0
  74. data/lib/conductor/http/models/poll_data.rb +33 -0
  75. data/lib/conductor/http/models/prompt_template.rb +59 -0
  76. data/lib/conductor/http/models/prompt_template_test_request.rb +43 -0
  77. data/lib/conductor/http/models/rerun_workflow_request.rb +37 -0
  78. data/lib/conductor/http/models/role.rb +27 -0
  79. data/lib/conductor/http/models/schema_def.rb +59 -0
  80. data/lib/conductor/http/models/search_result.rb +187 -0
  81. data/lib/conductor/http/models/skip_task_request.rb +27 -0
  82. data/lib/conductor/http/models/start_workflow_request.rb +68 -0
  83. data/lib/conductor/http/models/subject_ref.rb +35 -0
  84. data/lib/conductor/http/models/tag_object.rb +36 -0
  85. data/lib/conductor/http/models/target_ref.rb +39 -0
  86. data/lib/conductor/http/models/task.rb +156 -0
  87. data/lib/conductor/http/models/task_def.rb +95 -0
  88. data/lib/conductor/http/models/task_exec_log.rb +30 -0
  89. data/lib/conductor/http/models/task_result.rb +115 -0
  90. data/lib/conductor/http/models/task_result_status.rb +24 -0
  91. data/lib/conductor/http/models/token.rb +33 -0
  92. data/lib/conductor/http/models/upsert_group_request.rb +30 -0
  93. data/lib/conductor/http/models/upsert_user_request.rb +39 -0
  94. data/lib/conductor/http/models/workflow.rb +202 -0
  95. data/lib/conductor/http/models/workflow_def.rb +73 -0
  96. data/lib/conductor/http/models/workflow_schedule.rb +100 -0
  97. data/lib/conductor/http/models/workflow_state_update.rb +30 -0
  98. data/lib/conductor/http/models/workflow_status_constants.rb +57 -0
  99. data/lib/conductor/http/models/workflow_task.rb +169 -0
  100. data/lib/conductor/http/models/workflow_test_request.rb +67 -0
  101. data/lib/conductor/http/rest_client.rb +211 -0
  102. data/lib/conductor/orkes/models/access_key.rb +56 -0
  103. data/lib/conductor/orkes/models/granted_permission.rb +27 -0
  104. data/lib/conductor/orkes/models/metadata_tag.rb +15 -0
  105. data/lib/conductor/orkes/models/rate_limit_tag.rb +15 -0
  106. data/lib/conductor/orkes/orkes_clients.rb +69 -0
  107. data/lib/conductor/version.rb +5 -0
  108. data/lib/conductor/worker/events/conductor_event.rb +40 -0
  109. data/lib/conductor/worker/events/global_dispatcher.rb +37 -0
  110. data/lib/conductor/worker/events/http_events.rb +25 -0
  111. data/lib/conductor/worker/events/listener_registry.rb +40 -0
  112. data/lib/conductor/worker/events/listeners.rb +34 -0
  113. data/lib/conductor/worker/events/sync_event_dispatcher.rb +78 -0
  114. data/lib/conductor/worker/events/task_runner_events.rb +271 -0
  115. data/lib/conductor/worker/events/workflow_events.rb +49 -0
  116. data/lib/conductor/worker/fiber_executor.rb +532 -0
  117. data/lib/conductor/worker/ractor_task_runner.rb +501 -0
  118. data/lib/conductor/worker/task_context.rb +114 -0
  119. data/lib/conductor/worker/task_definition_registrar.rb +322 -0
  120. data/lib/conductor/worker/task_handler.rb +360 -0
  121. data/lib/conductor/worker/task_in_progress.rb +60 -0
  122. data/lib/conductor/worker/task_runner.rb +538 -0
  123. data/lib/conductor/worker/telemetry/metrics_collector.rb +196 -0
  124. data/lib/conductor/worker/telemetry/prometheus_backend.rb +224 -0
  125. data/lib/conductor/worker/worker.rb +355 -0
  126. data/lib/conductor/worker/worker_config.rb +154 -0
  127. data/lib/conductor/worker/worker_registry.rb +71 -0
  128. data/lib/conductor/workflow/dsl/input_ref.rb +37 -0
  129. data/lib/conductor/workflow/dsl/output_ref.rb +44 -0
  130. data/lib/conductor/workflow/dsl/parallel_builder.rb +49 -0
  131. data/lib/conductor/workflow/dsl/switch_builder.rb +74 -0
  132. data/lib/conductor/workflow/dsl/task_ref.rb +178 -0
  133. data/lib/conductor/workflow/dsl/workflow_builder.rb +1016 -0
  134. data/lib/conductor/workflow/dsl/workflow_definition.rb +150 -0
  135. data/lib/conductor/workflow/llm/chat_message.rb +47 -0
  136. data/lib/conductor/workflow/llm/embedding_model.rb +19 -0
  137. data/lib/conductor/workflow/llm/tool_call.rb +43 -0
  138. data/lib/conductor/workflow/llm/tool_spec.rb +46 -0
  139. data/lib/conductor/workflow/task_type.rb +68 -0
  140. data/lib/conductor/workflow/timeout_policy.rb +31 -0
  141. data/lib/conductor/workflow/workflow_executor.rb +373 -0
  142. data/lib/conductor.rb +192 -0
  143. metadata +359 -0
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Greetings Worker
4
+ # ================
5
+ # Simple worker that creates a greeting message.
6
+ # For detailed explanation: https://github.com/conductor-oss/ruby-sdk
7
+
8
+ require_relative '../../lib/conductor'
9
+
10
+ # Worker that creates a greeting message
11
+ class GreetingsWorker
12
+ include Conductor::Worker::WorkerModule
13
+
14
+ worker_task 'greet'
15
+
16
+ def execute(task)
17
+ name = get_input(task, 'name', 'World')
18
+ greeting = "Hello, #{name}!"
19
+
20
+ puts "[GreetingsWorker] Created greeting: #{greeting}"
21
+
22
+ { 'result' => greeting }
23
+ end
24
+ end
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Hello World Example
5
+ # ===================
6
+ #
7
+ # The simplest complete example demonstrating:
8
+ # 1. Define a workflow using the new Ruby-idiomatic DSL
9
+ # 2. Register the workflow
10
+ # 3. Start workers
11
+ # 4. Execute the workflow
12
+ # 5. Get the result
13
+ #
14
+ # Usage:
15
+ # cd examples/helloworld
16
+ # bundle exec ruby helloworld.rb
17
+ #
18
+ # Prerequisites:
19
+ # - Conductor server running (set CONDUCTOR_SERVER_URL env var)
20
+ # - For Orkes: Set CONDUCTOR_AUTH_KEY and CONDUCTOR_AUTH_SECRET
21
+
22
+ require_relative 'greetings_worker'
23
+
24
+ def create_greetings_workflow(executor)
25
+ # Define workflow using the new Ruby-idiomatic DSL
26
+ Conductor.workflow :greetings, version: 1, executor: executor do
27
+ # Create greet task that uses workflow input
28
+ # wf[:name] returns "${workflow.input.name}"
29
+ greet = simple :greet, name: wf[:name]
30
+
31
+ # Set output to be the result from greet task
32
+ # greet[:result] returns "${greet_ref.output.result}"
33
+ output result: greet[:result]
34
+ end
35
+ end
36
+
37
+ def main
38
+ # Configuration - reads from environment variables by default:
39
+ # CONDUCTOR_SERVER_URL: Conductor server URL (default: http://localhost:8080/api)
40
+ # CONDUCTOR_AUTH_KEY: API Authentication Key (optional for OSS)
41
+ # CONDUCTOR_AUTH_SECRET: API Auth Secret (optional for OSS)
42
+ config = Conductor::Configuration.new
43
+
44
+ puts '=' * 60
45
+ puts 'Conductor Ruby SDK - Hello World'
46
+ puts '=' * 60
47
+ puts
48
+ puts "Server: #{config.server_url}"
49
+ puts
50
+
51
+ # Create clients
52
+ clients = Conductor::Orkes::OrkesClients.new(config)
53
+ workflow_executor = clients.get_workflow_executor
54
+
55
+ # Create workflow with executor (required for register/execute)
56
+ workflow = create_greetings_workflow(workflow_executor)
57
+
58
+ # Register workflow (only needs to be done once)
59
+ puts 'Registering workflow...'
60
+ workflow.register(overwrite: true)
61
+ puts "Registered workflow: #{workflow.name} v#{workflow.version}"
62
+ puts
63
+
64
+ # Start workers
65
+ puts 'Starting workers...'
66
+ task_handler = Conductor::Worker::TaskRunner.new(config)
67
+ task_handler.register_worker(GreetingsWorker.new)
68
+ task_handler.start
69
+ puts 'Workers started!'
70
+ puts
71
+
72
+ # Execute workflow using the new DSL's execute method
73
+ puts 'Executing workflow with input: { name: "World" }'
74
+ workflow_run = workflow.execute(input: { 'name' => 'World' }, wait_for_seconds: 30)
75
+
76
+ puts
77
+ puts '-' * 60
78
+ puts "Workflow result: #{workflow_run.output['result']}"
79
+ puts '-' * 60
80
+ puts
81
+ puts "See the workflow execution at: #{config.ui_host}/execution/#{workflow_run.workflow_id}"
82
+
83
+ # Stop workers
84
+ task_handler.stop
85
+ puts
86
+ puts 'Done!'
87
+ end
88
+
89
+ if __FILE__ == $PROGRAM_NAME
90
+ begin
91
+ main
92
+ rescue Conductor::ApiError => e
93
+ puts "API Error: #{e.message}"
94
+ puts e.backtrace.first(5).join("\n")
95
+ rescue StandardError => e
96
+ puts "Error: #{e.message}"
97
+ puts e.backtrace.first(5).join("\n")
98
+ end
99
+ end
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Kitchen Sink Example
5
+ # ====================
6
+ #
7
+ # Comprehensive example demonstrating all major workflow task types and patterns
8
+ # using the new Ruby-idiomatic DSL.
9
+ #
10
+ # What it demonstrates:
11
+ # ---------------------
12
+ # - simple() - Custom worker tasks
13
+ # - http() - External API calls
14
+ # - javascript() - Inline JavaScript execution
15
+ # - jq() - JSON transformation with JQ
16
+ # - decide() - Conditional branching (switch)
17
+ # - wait() - Pause workflow execution
18
+ # - set() - Store workflow variables
19
+ # - terminate() - End workflow with specific status
20
+ # - sub_workflow() - Call another workflow
21
+ # - parallel() - Concurrent task execution
22
+ #
23
+ # Usage:
24
+ # bundle exec ruby examples/kitchensink.rb
25
+
26
+ require_relative '../lib/conductor'
27
+
28
+ # ============================================================================
29
+ # WORKER - Custom task implementation
30
+ # ============================================================================
31
+
32
+ class RouteWorker
33
+ include Conductor::Worker::WorkerModule
34
+
35
+ worker_task 'route'
36
+
37
+ def execute(task)
38
+ country = get_input(task, 'country', 'Unknown')
39
+ message = "routing the packages to #{country}"
40
+ puts "[RouteWorker] #{message}"
41
+ { 'result' => message }
42
+ end
43
+ end
44
+
45
+ def start_workers(config)
46
+ task_handler = Conductor::Worker::TaskRunner.new(config)
47
+ task_handler.register_worker(RouteWorker.new)
48
+ task_handler.start
49
+ task_handler
50
+ end
51
+
52
+ def create_sub_workflow(executor)
53
+ # Create a sub-workflow that will be called from the main workflow
54
+ Conductor.workflow :sub_ruby, version: 1, executor: executor do
55
+ # HTTP call using workflow input for URI
56
+ http :sub_call_api, url: wf[:uri]
57
+
58
+ # Wait for 2 seconds
59
+ wait 2
60
+ end
61
+ end
62
+
63
+ def create_kitchensink_workflow(executor)
64
+ # Main kitchen sink workflow using the new DSL
65
+ Conductor.workflow :kitchensink_ruby, version: 1, executor: executor do
66
+ # -------------------------------------------------------------------------
67
+ # 1. JavaScript Task - Execute inline JavaScript
68
+ # -------------------------------------------------------------------------
69
+ say_hello_js = <<~JS
70
+ function greetings() {
71
+ return {
72
+ "text": "hello " + $.name,
73
+ "url": "https://orkes-api-tester.orkesconductor.com/api"
74
+ }
75
+ }
76
+ greetings();
77
+ JS
78
+
79
+ js = javascript :hello_script, script: say_hello_js, name: wf[:name]
80
+
81
+ # -------------------------------------------------------------------------
82
+ # 2. Parallel Execution - HTTP call and sub-workflow run concurrently
83
+ # -------------------------------------------------------------------------
84
+ parallel do
85
+ # Branch 1: Call sub-workflow with URL from JS task
86
+ sub_workflow :call_sub_workflow, workflow: 'sub_ruby', version: 1, uri: js[:url]
87
+
88
+ # Branch 2: HTTP call followed by wait
89
+ http :call_remote_api, url: 'https://orkes-api-tester.orkesconductor.com/api'
90
+ wait 2
91
+ end
92
+
93
+ # -------------------------------------------------------------------------
94
+ # 3. JSON JQ Task - Transform JSON data
95
+ # -------------------------------------------------------------------------
96
+ jq :jq_process,
97
+ query: '{ key3: (.key1.value1 + .key2.value2) }',
98
+ key1: { 'value1' => %w[a b] },
99
+ key2: { 'value2' => %w[d e] }
100
+
101
+ # -------------------------------------------------------------------------
102
+ # 4. Set Variable Task - Store workflow variables
103
+ # -------------------------------------------------------------------------
104
+ set(
105
+ var1: 'value1',
106
+ var2: 42,
107
+ var3: %w[a b c]
108
+ )
109
+
110
+ # -------------------------------------------------------------------------
111
+ # 5. Switch Task - Conditional branching based on country
112
+ # -------------------------------------------------------------------------
113
+ decide wf[:country] do
114
+ on 'US' do
115
+ simple :route, country: wf[:country]
116
+ end
117
+
118
+ on 'CA' do
119
+ simple :route, country: wf[:country]
120
+ end
121
+
122
+ otherwise do
123
+ terminate :terminated, 'unsupported country'
124
+ end
125
+ end
126
+
127
+ # -------------------------------------------------------------------------
128
+ # Set workflow output
129
+ # -------------------------------------------------------------------------
130
+ output greetings: js[:output]
131
+ end
132
+ end
133
+
134
+ def main
135
+ # Configuration from environment variables
136
+ config = Conductor::Configuration.new
137
+
138
+ puts '=' * 70
139
+ puts 'Conductor Ruby SDK - Kitchen Sink Example (New DSL)'
140
+ puts '=' * 70
141
+ puts
142
+ puts "Server: #{config.server_url}"
143
+ puts
144
+
145
+ # Create clients
146
+ clients = Conductor::Orkes::OrkesClients.new(config)
147
+ workflow_executor = clients.get_workflow_executor
148
+
149
+ # Start workers
150
+ task_handler = start_workers(config)
151
+ puts 'Workers started...'
152
+ puts
153
+
154
+ # ============================================================================
155
+ # CREATE WORKFLOWS USING NEW DSL
156
+ # ============================================================================
157
+
158
+ sub_workflow = create_sub_workflow(workflow_executor)
159
+ main_workflow = create_kitchensink_workflow(workflow_executor)
160
+
161
+ # ============================================================================
162
+ # REGISTER SUB-WORKFLOW FIRST
163
+ # ============================================================================
164
+
165
+ puts 'Registering sub-workflow...'
166
+ sub_workflow.register(overwrite: true)
167
+ puts "Sub-workflow '#{sub_workflow.name}' registered!"
168
+ puts
169
+
170
+ # ============================================================================
171
+ # REGISTER AND EXECUTE MAIN WORKFLOW
172
+ # ============================================================================
173
+
174
+ puts 'Registering main workflow...'
175
+ main_workflow.register(overwrite: true)
176
+ puts "Main workflow '#{main_workflow.name}' registered!"
177
+ puts
178
+
179
+ puts 'Executing kitchen sink workflow...'
180
+ puts "Input: { name: 'Conductor Ruby', country: 'US' }"
181
+ puts
182
+
183
+ result = main_workflow.execute(
184
+ input: { 'name' => 'Conductor Ruby', 'country' => 'US' },
185
+ wait_for_seconds: 60
186
+ )
187
+
188
+ puts
189
+ puts 'Workflow completed!'
190
+ puts '-' * 70
191
+ puts "Workflow ID: #{result.workflow_id}"
192
+ puts "Status: #{result.status}"
193
+ puts "Output: #{result.output.inspect}"
194
+ puts
195
+ puts "See the execution at: #{config.ui_host}/execution/#{result.workflow_id}"
196
+
197
+ # Stop workers
198
+ task_handler.stop
199
+ puts
200
+ puts 'Workers stopped. Goodbye!'
201
+ end
202
+
203
+ if __FILE__ == $PROGRAM_NAME
204
+ begin
205
+ main
206
+ rescue Conductor::ApiError => e
207
+ puts "API Error: #{e.message}"
208
+ puts e.backtrace.first(5).join("\n")
209
+ rescue StandardError => e
210
+ puts "Error: #{e.message}"
211
+ puts e.backtrace.first(5).join("\n")
212
+ end
213
+ end
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Metadata Management Journey
5
+ #
6
+ # Demonstrates all metadata operations: workflow definitions,
7
+ # task definitions, and tagging.
8
+ #
9
+ # Usage:
10
+ # bundle exec ruby examples/metadata_journey.rb
11
+
12
+ require_relative '../lib/conductor'
13
+
14
+ class MetadataJourney
15
+ def initialize
16
+ @config = Conductor::Configuration.new
17
+ @clients = Conductor::Orkes::OrkesClients.new(@config)
18
+ @metadata = @clients.get_metadata_client
19
+
20
+ puts '=' * 70
21
+ puts 'Metadata Management Journey'
22
+ puts '=' * 70
23
+ puts "Server: #{@config.server_url}"
24
+ puts
25
+ end
26
+
27
+ def run
28
+ manage_task_definitions
29
+ manage_workflow_definitions
30
+ work_with_tags
31
+ cleanup
32
+ end
33
+
34
+ private
35
+
36
+ def manage_task_definitions
37
+ puts "\n--- Task Definitions ---"
38
+
39
+ # Create task definitions
40
+ tasks = [
41
+ {
42
+ 'name' => 'ruby_process_order',
43
+ 'description' => 'Process incoming orders',
44
+ 'retryCount' => 3,
45
+ 'retryLogic' => 'FIXED',
46
+ 'retryDelaySeconds' => 10,
47
+ 'timeoutSeconds' => 300,
48
+ 'responseTimeoutSeconds' => 60
49
+ },
50
+ {
51
+ 'name' => 'ruby_send_notification',
52
+ 'description' => 'Send customer notifications',
53
+ 'retryCount' => 2,
54
+ 'timeoutSeconds' => 60
55
+ },
56
+ {
57
+ 'name' => 'ruby_update_inventory',
58
+ 'description' => 'Update inventory counts',
59
+ 'retryCount' => 5,
60
+ 'timeoutSeconds' => 120
61
+ }
62
+ ]
63
+
64
+ tasks.each do |task|
65
+ @metadata.register_task_def(task)
66
+ puts "Created task: #{task['name']}"
67
+ end
68
+
69
+ # Get a specific task
70
+ task = @metadata.get_task_def('ruby_process_order')
71
+ puts "\nRetrieved task: #{task['name'] || task.name}"
72
+
73
+ # Get all tasks
74
+ all_tasks = @metadata.get_all_task_defs
75
+ puts "Total tasks in system: #{all_tasks.length}"
76
+
77
+ @created_tasks = tasks.map { |t| t['name'] }
78
+ end
79
+
80
+ def manage_workflow_definitions
81
+ puts "\n--- Workflow Definitions ---"
82
+
83
+ # Create workflow definition
84
+ workflow_def = {
85
+ 'name' => 'ruby_order_pipeline',
86
+ 'description' => 'Complete order processing pipeline',
87
+ 'version' => 1,
88
+ 'schemaVersion' => 2,
89
+ 'tasks' => [
90
+ {
91
+ 'name' => 'ruby_process_order',
92
+ 'taskReferenceName' => 'process_ref',
93
+ 'type' => 'SIMPLE',
94
+ 'inputParameters' => {
95
+ 'orderId' => '${workflow.input.orderId}'
96
+ }
97
+ },
98
+ {
99
+ 'name' => 'ruby_update_inventory',
100
+ 'taskReferenceName' => 'inventory_ref',
101
+ 'type' => 'SIMPLE',
102
+ 'inputParameters' => {
103
+ 'items' => '${process_ref.output.items}'
104
+ }
105
+ },
106
+ {
107
+ 'name' => 'ruby_send_notification',
108
+ 'taskReferenceName' => 'notify_ref',
109
+ 'type' => 'SIMPLE',
110
+ 'inputParameters' => {
111
+ 'customerId' => '${workflow.input.customerId}',
112
+ 'status' => '${inventory_ref.output.status}'
113
+ }
114
+ }
115
+ ],
116
+ 'outputParameters' => {
117
+ 'orderStatus' => '${notify_ref.output.status}'
118
+ },
119
+ 'timeoutSeconds' => 600
120
+ }
121
+
122
+ @metadata.register_workflow_def(workflow_def, overwrite: true)
123
+ puts "Created workflow: #{workflow_def['name']}"
124
+
125
+ # Get the workflow
126
+ wf = @metadata.get_workflow_def('ruby_order_pipeline')
127
+ puts "Retrieved workflow: #{wf['name'] || wf.name}"
128
+
129
+ # Get all workflows
130
+ all_workflows = @metadata.get_all_workflow_defs
131
+ puts "Total workflows in system: #{all_workflows.length}"
132
+
133
+ @created_workflow = workflow_def['name']
134
+ end
135
+
136
+ def work_with_tags
137
+ puts "\n--- Working with Tags ---"
138
+
139
+ # Tag a workflow
140
+ tags = [
141
+ { 'key' => 'team', 'value' => 'orders' },
142
+ { 'key' => 'environment', 'value' => 'development' }
143
+ ]
144
+
145
+ begin
146
+ @metadata.add_workflow_tag('ruby_order_pipeline', tags.first)
147
+ puts "Added tag to workflow: #{tags.first['key']}=#{tags.first['value']}"
148
+
149
+ # Get workflow tags
150
+ wf_tags = @metadata.get_workflow_tags('ruby_order_pipeline')
151
+ puts "Workflow tags: #{wf_tags.length}"
152
+ rescue StandardError => e
153
+ puts "Tag operations: #{e.message}"
154
+ end
155
+ end
156
+
157
+ def cleanup
158
+ puts "\n--- Cleanup ---"
159
+
160
+ # Delete workflow
161
+ begin
162
+ @metadata.unregister_workflow_def(@created_workflow, 1)
163
+ puts "Deleted workflow: #{@created_workflow}"
164
+ rescue StandardError => e
165
+ puts "Could not delete workflow: #{e.message}"
166
+ end
167
+
168
+ # Delete tasks
169
+ @created_tasks&.each do |name|
170
+ @metadata.unregister_task_def(name)
171
+ puts "Deleted task: #{name}"
172
+ rescue StandardError => e
173
+ puts "Could not delete #{name}: #{e.message}"
174
+ end
175
+
176
+ puts "\nMetadata journey complete!"
177
+ end
178
+ end
179
+
180
+ if __FILE__ == $PROGRAM_NAME
181
+ begin
182
+ MetadataJourney.new.run
183
+ rescue Conductor::ApiError => e
184
+ puts "API Error: #{e.message}"
185
+ rescue StandardError => e
186
+ puts "Error: #{e.message}"
187
+ puts e.backtrace.first(3).join("\n")
188
+ end
189
+ end