zenaton 0.5.3 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b08187623f70606c27295f86be811f71dd80188db775074adb36525e7eb2c93c
4
- data.tar.gz: 11656eb73d4e571e8603c403c40793904b3d94fb2d44c5a73791ea58ef874a86
3
+ metadata.gz: 3262580f994d9fab99ad54ad278b6f0f99611055a4b988dfd9049224cbb2ce52
4
+ data.tar.gz: 0df314ffedb3ed23d8e8753466bc5913453827bb1ed3cb05be068524819409db
5
5
  SHA512:
6
- metadata.gz: 1b0004ca3a2e9791578af89aeb735d09062eedd5bd77fc4cf098abdae564526310b166e37e84f6e272ae9288f2fe0649fa6cf587499bf906e6c6969b0b75b90d
7
- data.tar.gz: d94f70b29a3ff0b7f43bc5f38a0c00a05ebed2126439c08a50d202166d9670abc36e263f191b658f3d1472114c10322680de183caf15969638534aba62fbfe4a
6
+ metadata.gz: 430ccaed078e353fa8a5a3a102a9260f315fde7f50000b09edcb969561e5b4fec78e66471537c9fbe5dfbd032318cb8e9905fb0c0e4ea6d76f0912da79db261d
7
+ data.tar.gz: 06a0a71007724d2e0f052d2ca8345ca039770c97b31ac114ea42706f8ad1db456b7ac074cbe5a3904d435d37c4f086dfbfe64f2f7afeece12593633c1806b7a4
@@ -18,6 +18,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
18
18
 
19
19
  ### Security
20
20
 
21
+ ## [0.6.0] - 2019-10-02
22
+
23
+ ### Changed
24
+
25
+ - `start workflow` now uses the graphql client
26
+ - `start task` now uses the graphql client
27
+ - `kill workflow` now uses the graphql client
28
+ - `pause workflow` now uses the graphql client
29
+ - `resume workflow` now uses the graphql client
30
+ - `find workflow` now uses the graphql client
31
+
32
+
21
33
  ## [0.5.3] - 2019-10-02
22
34
 
23
35
  ### Added
@@ -37,6 +49,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
37
49
  - Added missing documentation for serialization.
38
50
  - Added `custom_id` argument for workflow schedule.
39
51
 
52
+ ### Removed
53
+
54
+ - Removed code from the client that pertained to the client mode
55
+
40
56
  ## [0.5.0] - 2019-08-27
41
57
  ### Changed
42
58
  - No longer load JSON core extensions. Use our own refinements to avoid clashes
@@ -137,7 +153,8 @@ available.
137
153
  ### Added
138
154
  - Initial release.
139
155
 
140
- [Unreleased]: https://github.com/zenaton/zenaton-ruby/compare/v0.5.3...HEAD
156
+ [Unreleased]: https://github.com/zenaton/zenaton-ruby/compare/v0.6.0...HEAD
157
+ [0.6.0]: https://github.com/zenaton/zenaton-ruby/compare/v0.5.3...v0.6.0
141
158
  [0.5.3]: https://github.com/zenaton/zenaton-ruby/compare/v0.5.2...v0.5.3
142
159
  [0.5.2]: https://github.com/zenaton/zenaton-ruby/compare/v0.5.1...v0.5.2
143
160
  [0.5.1]: https://github.com/zenaton/zenaton-ruby/compare/v0.5.0...v0.5.1
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zenaton (0.5.3)
4
+ zenaton (0.6.0)
5
5
  activesupport
6
6
  tzinfo-data
7
7
 
@@ -1,49 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'securerandom'
4
3
  require 'singleton'
5
- require 'zenaton/services/graphql'
4
+ require 'zenaton/services/graph_ql/client'
6
5
  require 'zenaton/services/http'
7
6
  require 'zenaton/services/properties'
8
7
  require 'zenaton/services/serializer'
9
- require 'zenaton/workflows/version'
10
8
 
11
9
  module Zenaton
12
10
  # Zenaton Client
13
11
  class Client
14
12
  include Singleton
15
13
 
16
- ZENATON_API_URL = 'https://api.zenaton.com/v1' # Zenaton api url
17
- ZENATON_GATEWAY_URL = 'https://gateway.zenaton.com/api' # Gateway url
18
14
  ZENATON_WORKER_URL = 'http://localhost' # Default worker url
19
15
  DEFAULT_WORKER_PORT = 4001 # Default worker port
20
16
  WORKER_API_VERSION = 'v_newton' # Default worker api version
21
17
 
22
- MAX_ID_SIZE = 256 # Limit on length of custom ids
23
-
24
18
  APP_ENV = 'app_env' # Parameter name for the application environment
25
19
  APP_ID = 'app_id' # Parameter name for the application ID
26
- API_TOKEN = 'api_token' # Parameter name for the API token
27
-
28
- ATTR_INTENT_ID = 'intent_id' # Internal parameter for retries
29
- ATTR_ID = 'custom_id' # Parameter name for custom ids
30
- ATTR_NAME = 'name' # Parameter name for workflow names
31
- ATTR_CANONICAL = 'canonical_name' # Parameter name for version name
32
- ATTR_DATA = 'data' # Parameter name for json payload
33
- ATTR_PROG = 'programming_language' # Parameter name for the language
34
- ATTR_MODE = 'mode' # Parameter name for the worker update mode
35
- # Parameter name for task maximum processing time
36
- ATTR_MAX_PROCESSING_TIME = 'maxProcessingTime'
37
-
38
- PROG = 'Ruby' # The current programming language
39
-
40
- EVENT_INPUT = 'event_input' # Parameter name for event input
41
- EVENT_NAME = 'event_name' # Parameter name for event name
42
- EVENT_DATA = 'event_data' # Parameter name for event data
43
-
44
- WORKFLOW_KILL = 'kill' # Worker update mode to stop a worker
45
- WORKFLOW_PAUSE = 'pause' # Worker udpate mode to pause a worker
46
- WORKFLOW_RUN = 'run' # Worker update mode to resume a worker
47
20
 
48
21
  attr_writer :app_id, :api_token, :app_env
49
22
 
@@ -63,7 +36,7 @@ module Zenaton
63
36
  # @private
64
37
  def initialize
65
38
  @http = Services::Http.new
66
- @graphql = Services::GraphQL.new(http: @http)
39
+ @graphql = Services::GraphQL::Client.new(http: @http)
67
40
  @serializer = Services::Serializer.new
68
41
  @properties = Services::Properties.new
69
42
  end
@@ -84,133 +57,52 @@ module Zenaton
84
57
  end
85
58
  end
86
59
 
87
- def gateway_url
88
- ENV['ZENATON_GATEWAY_URL'] || ZENATON_GATEWAY_URL
89
- end
90
-
91
- def gateway_headers
92
- {
93
- 'app-id' => @app_id,
94
- 'api-token' => @api_token
95
- }
96
- end
97
-
98
- # Gets the url for zenaton api
99
- # @param resource [String] the endpoint for the api
100
- # @param params [Hash|String] query params to be url encoded
101
- # @return [String] the api url with parameters
102
- def website_url(resource = '', params = {})
103
- api_url = ENV['ZENATON_API_URL'] || ZENATON_API_URL
104
- url = "#{api_url}/#{resource}"
105
-
106
- if params.is_a?(Hash)
107
- params[API_TOKEN] = @api_token
108
- append_params_to_url(url, params)
109
- else
110
- add_app_env("#{url}?#{API_TOKEN}=#{@api_token}&", params)
111
- end
112
- end
113
-
114
60
  # Start a single task
115
61
  # @param task [Zenaton::Interfaces::Task]
116
62
  def start_task(task)
117
- max_processing_time = task.try(:max_processing_time)
118
- @http.post(
119
- worker_url('tasks'),
120
- ATTR_INTENT_ID => SecureRandom.uuid,
121
- ATTR_PROG => PROG,
122
- ATTR_NAME => class_name(task),
123
- ATTR_DATA => @serializer.encode(@properties.from(task)),
124
- ATTR_MAX_PROCESSING_TIME => max_processing_time
125
- )
63
+ @graphql.start_task(task, credentials)
126
64
  end
127
65
 
128
66
  # Start the specified workflow
129
67
  # @param flow [Zenaton::Interfaces::Workflow]
130
68
  def start_workflow(flow)
131
- @http.post(
132
- instance_worker_url,
133
- ATTR_INTENT_ID => SecureRandom.uuid,
134
- ATTR_PROG => PROG,
135
- ATTR_CANONICAL => canonical_name(flow),
136
- ATTR_NAME => class_name(flow),
137
- ATTR_DATA => @serializer.encode(@properties.from(flow)),
138
- ATTR_ID => parse_custom_id_from(flow)
139
- )
69
+ @graphql.start_workflow(flow, credentials)
140
70
  end
141
71
 
72
+ # Schedule a task for repeated execution
142
73
  def start_scheduled_task(task, cron)
143
- res = @graphql.request(
144
- gateway_url,
145
- Services::GraphQL::CREATE_TASK_SCHEDULE,
146
- create_task_schedule_input(task, cron),
147
- gateway_headers
148
- )
74
+ res = @graphql.schedule_task(task, cron, credentials)
149
75
  res && res['createTaskSchedule']
150
76
  end
151
77
 
78
+ # Schedule a workflow for repeated execution
152
79
  def start_scheduled_workflow(flow, cron)
153
- res = @graphql.request(
154
- gateway_url,
155
- Services::GraphQL::CREATE_WORKFLOW_SCHEDULE,
156
- create_workflow_schedule_input(flow, cron),
157
- gateway_headers
158
- )
80
+ res = @graphql.schedule_workflow(flow, cron, credentials)
159
81
  res && res['createWorkflowSchedule']
160
82
  end
161
83
 
162
- # rubocop:disable Metrics/MethodLength
163
- def create_workflow_schedule_input(flow, cron)
164
- {
165
- 'createWorkflowScheduleInput' => {
166
- 'intentId' => SecureRandom.uuid,
167
- 'environmentName' => @app_env,
168
- 'cron' => cron,
169
- 'customId' => parse_custom_id_from(flow),
170
- 'workflowName' => class_name(flow),
171
- 'canonicalName' => canonical_name(flow) || class_name(flow),
172
- 'programmingLanguage' => PROG.upcase,
173
- 'properties' => @serializer.encode(@properties.from(flow))
174
- }
175
- }
176
- end
177
- # rubocop:enable Metrics/MethodLength
178
-
179
- def create_task_schedule_input(task, cron)
180
- {
181
- 'createTaskScheduleInput' => {
182
- 'intentId' => SecureRandom.uuid,
183
- 'environmentName' => @app_env,
184
- 'cron' => cron,
185
- 'taskName' => class_name(task),
186
- 'programmingLanguage' => PROG.upcase,
187
- 'properties' => @serializer.encode(@properties.from(task))
188
- }
189
- }
190
- end
191
-
192
84
  # Stops a workflow
193
- # @param workflow_name [String] the class name of the workflow
194
- # @param custom_id [String] the custom ID of the workflow (if any)
85
+ # @param name [String] the class name of the workflow
86
+ # @param custom_id [String] the custom ID of the workflow
195
87
  # @return [NilClass]
196
- def kill_workflow(workflow_name, custom_id)
197
- update_instance(workflow_name, custom_id, WORKFLOW_KILL)
88
+ def kill_workflow(name, custom_id)
89
+ @graphql.kill_workflow(name, custom_id, credentials)
198
90
  end
199
91
 
200
92
  # Pauses a workflow
201
- # @param workflow_name [String] the class name of the workflow
202
- # @param custom_id [String] the custom ID of the workflow (if any)
93
+ # @param name [String] the class name of the workflow
94
+ # @param custom_id [String] the custom ID of the workflow
203
95
  # @return [NilClass]
204
- def pause_workflow(workflow_name, custom_id)
205
- update_instance(workflow_name, custom_id, WORKFLOW_PAUSE)
96
+ def pause_workflow(name, custom_id)
97
+ @graphql.pause_workflow(name, custom_id, credentials)
206
98
  end
207
99
 
208
100
  # Resumes a workflow
209
- # @param workflow_name [String] the class name of the workflow
210
- # @param custom_id [String] the custom ID of the workflow (if any)
101
+ # @param name [String] the class name of the workflow
102
+ # @param custom_id [String] the custom ID of the workflow
211
103
  # @return [NilClass]
212
- def resume_workflow(workflow_name, custom_id)
213
- update_instance(workflow_name, custom_id, WORKFLOW_RUN)
104
+ def resume_workflow(name, custom_id)
105
+ @graphql.resume_workflow(name, custom_id, credentials)
214
106
  end
215
107
 
216
108
  # Finds a workflow
@@ -218,38 +110,28 @@ module Zenaton
218
110
  # @param custom_id [String] the custom ID of the workflow
219
111
  # @return [Zenaton::Interfaces::Workflow, nil]
220
112
  def find_workflow(workflow_name, custom_id)
221
- params = { ATTR_ID => custom_id, ATTR_NAME => workflow_name }
222
- params[ATTR_PROG] = PROG
223
- data = @http.get(instance_website_url(params))['data']
224
- data && @properties.object_from(
225
- data['name'],
226
- @serializer.decode(data['properties'])
227
- )
228
- rescue Zenaton::InternalError => exception
229
- return nil if exception.message =~ /No workflow instance found/
230
- raise exception
113
+ @graphql.find_workflow(workflow_name, custom_id, credentials)
231
114
  end
232
115
 
233
116
  # Sends an event to a workflow
234
117
  # @param workflow_name [String] the class name of the workflow
235
- # @param custom_id [String] the custom ID of the workflow (if any)
118
+ # @param custom_id [String] the custom ID of the workflow
236
119
  # @param event [Zenaton::Interfaces::Event] the event to send
237
120
  # @return [NilClass]
238
121
  def send_event(workflow_name, custom_id, event)
239
- body = {
240
- ATTR_INTENT_ID => SecureRandom.uuid,
241
- ATTR_PROG => PROG,
242
- ATTR_NAME => workflow_name,
243
- ATTR_ID => custom_id,
244
- EVENT_NAME => event.class.name,
245
- EVENT_INPUT => @serializer.encode(@properties.from(event)),
246
- EVENT_DATA => @serializer.encode(event)
247
- }
248
- @http.post(send_event_url, body)
122
+ @graphql.send_event(workflow_name, custom_id, event, credentials)
249
123
  end
250
124
 
251
125
  private
252
126
 
127
+ def credentials
128
+ {
129
+ 'app_id' => @app_id,
130
+ 'api_token' => @api_token,
131
+ 'app_env' => @app_env
132
+ }
133
+ end
134
+
253
135
  # DEPRECATED: This implementation does not safely encode the parameters to
254
136
  # be passed as query params in a get request. This method gets called by
255
137
  # agents up to version 0.4.5
@@ -272,56 +154,5 @@ module Zenaton
272
154
 
273
155
  "#{url}?#{URI.encode_www_form(params)}"
274
156
  end
275
-
276
- def instance_website_url(params)
277
- website_url('instances', params)
278
- end
279
-
280
- def instance_worker_url(params = {})
281
- worker_url('instances', params)
282
- end
283
-
284
- def send_event_url
285
- worker_url('events')
286
- end
287
-
288
- # rubocop:disable Metrics/MethodLength
289
- def parse_custom_id_from(flow)
290
- custom_id = flow.id
291
- if custom_id
292
- unless custom_id.is_a?(String) || custom_id.is_a?(Integer)
293
- raise InvalidArgumentError,
294
- 'Provided ID must be a string or an integer'
295
- end
296
- custom_id = custom_id.to_s
297
- if custom_id.length > MAX_ID_SIZE
298
- raise InvalidArgumentError,
299
- "Provided Id must not exceed #{MAX_ID_SIZE} bytes"
300
- end
301
- end
302
- custom_id
303
- end
304
- # rubocop:enable Metrics/MethodLength
305
-
306
- def canonical_name(flow)
307
- flow.class.name if flow.is_a? Workflows::Version
308
- end
309
-
310
- def class_name(flow)
311
- return flow.class.name unless flow.is_a? Workflows::Version
312
- flow.current_implementation.class.name
313
- end
314
-
315
- def update_instance(workflow_name, custom_id, mode)
316
- params = { ATTR_ID => custom_id }
317
- url = instance_worker_url(params)
318
- options = {
319
- ATTR_INTENT_ID => SecureRandom.uuid,
320
- ATTR_PROG => PROG,
321
- ATTR_NAME => workflow_name,
322
- ATTR_MODE => mode
323
- }
324
- @http.put(url, options)
325
- end
326
157
  end
327
158
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+ require 'zenaton/workflows/version'
5
+ require 'zenaton/exceptions'
6
+
7
+ module Zenaton
8
+ # Composable modules available for reuse
9
+ module Concerns
10
+ # Utility methods for classes that interact with workflows
11
+ # Requires an instance variable @workflow to work
12
+ module Workflow
13
+ extend ActiveSupport::Concern
14
+
15
+ MAX_ID_SIZE = 256 # Maximum length for custom ids
16
+
17
+ private
18
+
19
+ # Determines the name of the workflow
20
+ def workflow_name
21
+ if @workflow.is_a? Workflows::Version
22
+ @workflow.current_implementation.class.name
23
+ else
24
+ @workflow.class.name
25
+ end
26
+ end
27
+
28
+ # Validation for the return value of the [#id] method
29
+ def validate_custom_id
30
+ return unless @workflow.try(:id).present?
31
+
32
+ validate_custom_id_type
33
+ validate_custom_id_value
34
+ end
35
+
36
+ # Only allow String and Integers as custom IDs
37
+ def validate_custom_id_type
38
+ valid_types = [String, Integer]
39
+ return if valid_types.any? { |type| @workflow.id.is_a?(type) }
40
+
41
+ raise InvalidArgumentError,
42
+ 'Provided ID must be a string or an integer' \
43
+ end
44
+
45
+ # Enforce maximum size on custom IDs
46
+ def validate_custom_id_value
47
+ return if @workflow.id.to_s.length <= MAX_ID_SIZE
48
+
49
+ raise InvalidArgumentError,
50
+ "Provided Id must not exceed #{MAX_ID_SIZE} bytes"
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'zenaton/exceptions'
5
+ require 'zenaton/services/properties'
6
+ require 'zenaton/services/serializer'
7
+
8
+ module Zenaton
9
+ module Services
10
+ module GraphQL
11
+ # @abstract Superclass for graphql queries and mutations.
12
+ # It expects two methods to be implemented in children classes:
13
+ # - #body
14
+ # - #raw_query
15
+ class BaseOperation
16
+ # Sets up common dependencies for serialization
17
+ # Don't forget to call #super in your children #initialize if
18
+ # overriding this method.
19
+ def initialize(*)
20
+ @serializer = Services::Serializer.new
21
+ @properties = Services::Properties.new
22
+ end
23
+
24
+ # To be implemented in subclasses.
25
+ # Should return the body of the GraphQL request
26
+ # @raise [NotImplemented]
27
+ def body
28
+ raise NotImplemented
29
+ end
30
+
31
+ # To be implemented in subclasses.
32
+ # The actual GraphQL query
33
+ # @raise [NotImplemented]
34
+ def raw_query
35
+ raise NotImplemented
36
+ end
37
+
38
+ # Default implementation for parsing GraphQL responses
39
+ # Override in subclasses if needed.
40
+ # @raise [NotImplemented]
41
+ def result(response)
42
+ raise Zenaton::ExternalError, format_errors(response) \
43
+ if response['errors']
44
+
45
+ response['data']
46
+ end
47
+
48
+ # Removes duplicate white space from the raw_query
49
+ # @return [String]
50
+ def query
51
+ raw_query.gsub(/\s+/, ' ')
52
+ end
53
+
54
+ # Sets an unique identifier to the query
55
+ # @return [String]
56
+ def intent_id
57
+ SecureRandom.uuid
58
+ end
59
+
60
+ private
61
+
62
+ def format_errors(response)
63
+ response['errors'].map(&method(:format_error))
64
+ .join("\n")
65
+ end
66
+
67
+ def format_error(error)
68
+ if error['path']
69
+ "- #{error['path']}: #{error['message']}"
70
+ else
71
+ "- #{error['message']}"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/create_workflow_schedule_mutation'
4
+ require 'zenaton/services/graph_ql/create_task_schedule_mutation'
5
+ require 'zenaton/services/graph_ql/dispatch_task_mutation'
6
+ require 'zenaton/services/graph_ql/dispatch_workflow_mutation'
7
+ require 'zenaton/services/graph_ql/kill_workflow_mutation'
8
+ require 'zenaton/services/graph_ql/pause_workflow_mutation'
9
+ require 'zenaton/services/graph_ql/resume_workflow_mutation'
10
+ require 'zenaton/services/graph_ql/send_event_mutation'
11
+ require 'zenaton/services/graph_ql/workflow_query'
12
+
13
+ module Zenaton
14
+ module Services
15
+ # Module for client, mutations and queries used to communicate with
16
+ # Zenaton's GraphQL API
17
+ module GraphQL
18
+ # Small client to interact with Zenaton's GraphQL API
19
+ class Client
20
+ ZENATON_GATEWAY_URL = 'https://gateway.zenaton.com/api' # Gateway url
21
+
22
+ # Setup the GraphQL client with the HTTP client to use
23
+ def initialize(http:)
24
+ @http = http
25
+ end
26
+
27
+ # Scheduling a workflow
28
+ def schedule_workflow(workflow, cron, credentials)
29
+ app_env = credentials['app_env']
30
+ mutation = CreateWorkflowScheduleMutation.new(workflow, cron, app_env)
31
+ execute(mutation, credentials)
32
+ end
33
+
34
+ # Scheduling a task
35
+ def schedule_task(task, cron, credentials)
36
+ app_env = credentials['app_env']
37
+ mutation = CreateTaskScheduleMutation.new(task, cron, app_env)
38
+ execute(mutation, credentials)
39
+ end
40
+
41
+ # Dispatching a single task
42
+ def start_task(task, credentials)
43
+ app_env = credentials['app_env']
44
+ mutation = DispatchTaskMutation.new(task, app_env)
45
+ execute(mutation, credentials)
46
+ end
47
+
48
+ # Dispatching a workflow
49
+ def start_workflow(workflow, credentials)
50
+ app_env = credentials['app_env']
51
+ mutation = DispatchWorkflowMutation.new(workflow, app_env)
52
+ execute(mutation, credentials)
53
+ end
54
+
55
+ # Stopping an existing workflow
56
+ def kill_workflow(name, custom_id, credentials)
57
+ app_env = credentials['app_env']
58
+ mutation = KillWorkflowMutation.new(name, custom_id, app_env)
59
+ execute(mutation, credentials)
60
+ end
61
+
62
+ # Pausing an existing workflow
63
+ def pause_workflow(name, custom_id, credentials)
64
+ app_env = credentials['app_env']
65
+ mutation = PauseWorkflowMutation.new(name, custom_id, app_env)
66
+ execute(mutation, credentials)
67
+ end
68
+
69
+ # Resuming a paused workflow
70
+ def resume_workflow(name, custom_id, credentials)
71
+ app_env = credentials['app_env']
72
+ mutation = ResumeWorkflowMutation.new(name, custom_id, app_env)
73
+ execute(mutation, credentials)
74
+ end
75
+
76
+ # Sending an event to an existing workflow
77
+ def send_event(name, custom_id, event, credentials)
78
+ app_env = credentials['app_env']
79
+ mutation = SendEventMutation.new(name, custom_id, event, app_env)
80
+ execute(mutation, credentials)
81
+ end
82
+
83
+ # Search for a workflow with a custom ID
84
+ def find_workflow(name, custom_id, credentials)
85
+ app_env = credentials['app_env']
86
+ query = WorkflowQuery.new(name, custom_id, app_env)
87
+ execute(query, credentials)
88
+ end
89
+
90
+ private
91
+
92
+ def url
93
+ ENV['ZENATON_GATEWAY_URL'] || ZENATON_GATEWAY_URL
94
+ end
95
+
96
+ def headers(credentials)
97
+ {
98
+ 'app-id' => credentials['app_id'],
99
+ 'api-token' => credentials['api_token']
100
+ }
101
+ end
102
+
103
+ def execute(operation, credentials)
104
+ response = @http.post(url, operation.body, headers(credentials))
105
+ operation.result(response)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/base_operation'
4
+
5
+ module Zenaton
6
+ module Services
7
+ module GraphQL
8
+ # Mutation parameters for scheduling a Task
9
+ class CreateTaskScheduleMutation < BaseOperation
10
+ def initialize(task, cron, app_env)
11
+ super
12
+ @task = task
13
+ @cron = cron
14
+ @app_env = app_env
15
+ end
16
+
17
+ # The body of the GraphQL request
18
+ def body
19
+ { 'query' => query, 'variables' => variables }
20
+ end
21
+
22
+ # The query to be executed
23
+ def raw_query
24
+ <<~GQL
25
+ mutation ($input: CreateTaskScheduleInput!) {
26
+ createTaskSchedule(input: $input) {
27
+ schedule {
28
+ id
29
+ }
30
+ }
31
+ }
32
+ GQL
33
+ end
34
+
35
+ # The variables used in the query
36
+ def variables
37
+ {
38
+ 'input' => {
39
+ 'intentId' => intent_id,
40
+ 'environmentName' => @app_env,
41
+ 'cron' => @cron,
42
+ 'taskName' => @task.class.name,
43
+ 'programmingLanguage' => 'RUBY',
44
+ 'properties' => @serializer.encode(@properties.from(@task))
45
+ }
46
+ }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/base_operation'
4
+ require 'zenaton/concerns/workflow'
5
+
6
+ module Zenaton
7
+ module Services
8
+ module GraphQL
9
+ # Mutation parameters for scheduling a Task
10
+ class CreateWorkflowScheduleMutation < BaseOperation
11
+ include Concerns::Workflow
12
+
13
+ # @raise [Zenaton::InvalidArgumentError] if custom id fails validation
14
+ def initialize(workflow, cron, app_env)
15
+ super
16
+ @workflow = workflow
17
+ @cron = cron
18
+ @app_env = app_env
19
+ validate_custom_id
20
+ end
21
+
22
+ # The body of the GraphQL request
23
+ def body
24
+ { 'query' => query, 'variables' => variables }
25
+ end
26
+
27
+ # The query to be executed
28
+ def raw_query
29
+ <<~GQL
30
+ mutation ($input: CreateWorkflowScheduleInput!) {
31
+ createWorkflowSchedule(input: $input) {
32
+ schedule {
33
+ id
34
+ }
35
+ }
36
+ }
37
+ GQL
38
+ end
39
+
40
+ # The variables used in the query
41
+ def variables
42
+ { 'input' => input }
43
+ end
44
+
45
+ private
46
+
47
+ def input
48
+ {
49
+ 'intentId' => intent_id,
50
+ 'environmentName' => @app_env,
51
+ 'cron' => @cron,
52
+ 'customId' => @workflow.id.try(:to_s),
53
+ 'workflowName' => workflow_name,
54
+ 'canonicalName' => @workflow.class.name,
55
+ 'programmingLanguage' => 'RUBY',
56
+ 'properties' => @serializer.encode(@properties.from(@workflow))
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/base_operation'
4
+
5
+ module Zenaton
6
+ module Services
7
+ module GraphQL
8
+ # Mutation parameters for executing a single task
9
+ class DispatchTaskMutation < BaseOperation
10
+ def initialize(task, app_env)
11
+ super
12
+ @task = task
13
+ @app_env = app_env
14
+ end
15
+
16
+ # The body of the GraphQL request
17
+ def body
18
+ { 'query' => query, 'variables' => variables }
19
+ end
20
+
21
+ # The query to be executed
22
+ def raw_query
23
+ <<~GQL
24
+ mutation dispatchTask($input: DispatchTaskInput!) {
25
+ dispatchTask(input: $input) {
26
+ task {
27
+ intentId
28
+ }
29
+ }
30
+ }
31
+ GQL
32
+ end
33
+
34
+ # The variables used in the query
35
+ def variables
36
+ {
37
+ 'input' => {
38
+ 'environmentName' => @app_env,
39
+ 'intentId' => intent_id,
40
+ 'name' => @task.class.name,
41
+ 'maxProcessingTime' => @task.try(:max_processing_time),
42
+ 'programmingLanguage' => 'RUBY',
43
+ 'data' => @serializer.encode(@properties.from(@task))
44
+ }
45
+ }
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/base_operation'
4
+ require 'zenaton/concerns/workflow'
5
+
6
+ module Zenaton
7
+ module Services
8
+ module GraphQL
9
+ # Mutation parameters for executing a workflow
10
+ class DispatchWorkflowMutation < BaseOperation
11
+ include Concerns::Workflow
12
+
13
+ # @raise [Zenaton::InvalidArgumentError] if custom id fails validation
14
+ def initialize(workflow, app_env)
15
+ super
16
+ @workflow = workflow
17
+ @app_env = app_env
18
+ validate_custom_id
19
+ end
20
+
21
+ # The body of the GraphQL request
22
+ def body
23
+ { 'query' => query, 'variables' => variables }
24
+ end
25
+
26
+ # The query to be executed
27
+ def raw_query
28
+ <<~GQL
29
+ mutation dispatchWorkflow($input: DispatchWorkflowInput!) {
30
+ dispatchWorkflow(input: $input) {
31
+ workflow {
32
+ id
33
+ }
34
+ }
35
+ }
36
+ GQL
37
+ end
38
+
39
+ # rubocop:disable Metrics/MethodLength
40
+ # The variables used in the query
41
+ def variables
42
+ {
43
+ 'input' => {
44
+ 'customId' => @workflow.id.try(:to_s),
45
+ 'environmentName' => @app_env,
46
+ 'intentId' => intent_id,
47
+ 'programmingLanguage' => 'RUBY',
48
+ 'name' => workflow_name,
49
+ 'canonicalName' => @workflow.class.name,
50
+ 'data' => @serializer.encode(@properties.from(@workflow))
51
+ }
52
+ }
53
+ end
54
+ # rubocop:enable Metrics/MethodLength
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/base_operation'
4
+
5
+ module Zenaton
6
+ module Services
7
+ module GraphQL
8
+ # Mutation parameters for stopping a workflow
9
+ class KillWorkflowMutation < BaseOperation
10
+ def initialize(name, custom_id, app_env)
11
+ super
12
+ @name = name
13
+ @custom_id = custom_id
14
+ @app_env = app_env
15
+ end
16
+
17
+ # The body of the GraphQL request
18
+ def body
19
+ { 'query' => query, 'variables' => variables }
20
+ end
21
+
22
+ # The query to be executed
23
+ def raw_query
24
+ <<~GQL
25
+ mutation killWorkflow($input: KillWorkflowInput!) {
26
+ killWorkflow(input: $input) {
27
+ id
28
+ }
29
+ }
30
+ GQL
31
+ end
32
+
33
+ # The variables used in the query
34
+ def variables
35
+ {
36
+ 'input' => {
37
+ 'customId' => @custom_id,
38
+ 'environmentName' => @app_env,
39
+ 'intentId' => intent_id,
40
+ 'programmingLanguage' => 'RUBY',
41
+ 'name' => @name
42
+ }
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/base_operation'
4
+
5
+ module Zenaton
6
+ module Services
7
+ module GraphQL
8
+ # Mutation parameters for pausing a Workflow
9
+ class PauseWorkflowMutation < BaseOperation
10
+ def initialize(name, custom_id, app_env)
11
+ super
12
+ @name = name
13
+ @custom_id = custom_id
14
+ @app_env = app_env
15
+ end
16
+
17
+ # The body of the GraphQL request
18
+ def body
19
+ { 'query' => query, 'variables' => variables }
20
+ end
21
+
22
+ # The query to be executed
23
+ def raw_query
24
+ <<~GQL
25
+ mutation pauseWorkflow($input: PauseWorkflowInput!) {
26
+ pauseWorkflow(input: $input) {
27
+ id
28
+ }
29
+ }
30
+ GQL
31
+ end
32
+
33
+ # The variables used in the query
34
+ def variables
35
+ {
36
+ 'input' => {
37
+ 'customId' => @custom_id,
38
+ 'environmentName' => @app_env,
39
+ 'intentId' => intent_id,
40
+ 'programmingLanguage' => 'RUBY',
41
+ 'name' => @name
42
+ }
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/base_operation'
4
+
5
+ module Zenaton
6
+ module Services
7
+ module GraphQL
8
+ # Mutation parameters for resuming a paused Workflow
9
+ class ResumeWorkflowMutation < BaseOperation
10
+ def initialize(name, custom_id, app_env)
11
+ super
12
+ @name = name
13
+ @custom_id = custom_id
14
+ @app_env = app_env
15
+ end
16
+
17
+ # The body of the GraphQL request
18
+ def body
19
+ { 'query' => query, 'variables' => variables }
20
+ end
21
+
22
+ # The query to be executed
23
+ def raw_query
24
+ <<~GQL
25
+ mutation resumeWorkflow($input: ResumeWorkflowInput!) {
26
+ resumeWorkflow(input: $input) {
27
+ id
28
+ }
29
+ }
30
+ GQL
31
+ end
32
+
33
+ # The variables used in the query
34
+ def variables
35
+ {
36
+ 'input' => {
37
+ 'customId' => @custom_id,
38
+ 'environmentName' => @app_env,
39
+ 'intentId' => intent_id,
40
+ 'programmingLanguage' => 'RUBY',
41
+ 'name' => @name
42
+ }
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/base_operation'
4
+
5
+ module Zenaton
6
+ module Services
7
+ module GraphQL
8
+ # Mutation parameters for sending an Event to a Workflow
9
+ class SendEventMutation < BaseOperation
10
+ def initialize(name, custom_id, event, app_env)
11
+ super
12
+ @workflow_name = name
13
+ @custom_id = custom_id
14
+ @event = event
15
+ @app_env = app_env
16
+ end
17
+
18
+ # The body of the GraphQL request
19
+ def body
20
+ { 'query' => query, 'variables' => variables }
21
+ end
22
+
23
+ # The query to be executed
24
+ def raw_query
25
+ <<~GQL
26
+ mutation sendEventToWorkflowByNameAndCustomId($input: SendEventToWorkflowByNameAndCustomIdInput!) {
27
+ sendEventToWorkflowByNameAndCustomId(input: $input) {
28
+ event {
29
+ intentId
30
+ }
31
+ }
32
+ }
33
+ GQL
34
+ end
35
+
36
+ # The variables used in the query
37
+ def variables
38
+ { 'input' => input }
39
+ end
40
+
41
+ private
42
+
43
+ def input
44
+ {
45
+ 'customId' => @custom_id,
46
+ 'workflowName' => @workflow_name,
47
+ 'name' => @event.class.name,
48
+ 'environmentName' => @app_env,
49
+ 'intentId' => intent_id,
50
+ 'programmingLanguage' => 'RUBY',
51
+ 'input' => @serializer.encode(@properties.from(@event)),
52
+ 'data' => @serializer.encode(@event)
53
+ }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zenaton/services/graph_ql/base_operation'
4
+
5
+ module Zenaton
6
+ module Services
7
+ module GraphQL
8
+ # Query parameters to search for a Workflow
9
+ class WorkflowQuery < BaseOperation
10
+ def initialize(workflow_name, custom_id, app_env)
11
+ super
12
+ @workflow_name = workflow_name
13
+ @custom_id = custom_id
14
+ @app_env = app_env
15
+ end
16
+
17
+ # The body of the GraphQL request
18
+ def body
19
+ { 'query' => query, 'variables' => variables }
20
+ end
21
+
22
+ # The query to be executed
23
+ def raw_query
24
+ <<~GQL
25
+ query ($workflowName: String, $customId: ID, $environmentName: String, $programmingLanguage: String) {
26
+ findWorkflow(environmentName: $environmentName, programmingLanguage: $programmingLanguage, customId: $customId, name: $workflowName) {
27
+ name
28
+ properties
29
+ }
30
+ }
31
+ GQL
32
+ end
33
+
34
+ # The variables used in the query
35
+ def variables
36
+ {
37
+ 'customId' => @custom_id,
38
+ 'environmentName' => @app_env,
39
+ 'programmingLanguage' => 'RUBY',
40
+ 'workflowName' => @workflow_name
41
+ }
42
+ end
43
+
44
+ # Parses the results of the query
45
+ def result(response)
46
+ data = response['data']
47
+ raise Zenaton::ExternalError, format_errors(response) unless data
48
+
49
+ return nil if data['findWorkflow'].nil?
50
+
51
+ @properties.object_from(
52
+ data['findWorkflow']['name'],
53
+ @serializer.decode(data['findWorkflow']['properties'])
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -22,6 +22,7 @@ module Zenaton
22
22
  Engine.instance.dispatch([self])
23
23
  end
24
24
 
25
+ # Sets the repeatable frequency of execution of a given job
25
26
  def schedule(cron)
26
27
  if !cron.is_a?(String) || cron.blank?
27
28
  raise InvalidArgumentError,
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Zenaton
4
4
  # This gem's current version
5
- VERSION = '0.5.3'
5
+ VERSION = '0.6.0'
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zenaton
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zenaton
@@ -234,6 +234,7 @@ files:
234
234
  - gemfiles/rails_5.2.gemfile
235
235
  - lib/zenaton.rb
236
236
  - lib/zenaton/client.rb
237
+ - lib/zenaton/concerns/workflow.rb
237
238
  - lib/zenaton/contexts.rb
238
239
  - lib/zenaton/contexts/task.rb
239
240
  - lib/zenaton/contexts/workflow.rb
@@ -261,7 +262,17 @@ files:
261
262
  - lib/zenaton/refinements/struct.rb
262
263
  - lib/zenaton/refinements/symbol.rb
263
264
  - lib/zenaton/refinements/time.rb
264
- - lib/zenaton/services/graphql.rb
265
+ - lib/zenaton/services/graph_ql/base_operation.rb
266
+ - lib/zenaton/services/graph_ql/client.rb
267
+ - lib/zenaton/services/graph_ql/create_task_schedule_mutation.rb
268
+ - lib/zenaton/services/graph_ql/create_workflow_schedule_mutation.rb
269
+ - lib/zenaton/services/graph_ql/dispatch_task_mutation.rb
270
+ - lib/zenaton/services/graph_ql/dispatch_workflow_mutation.rb
271
+ - lib/zenaton/services/graph_ql/kill_workflow_mutation.rb
272
+ - lib/zenaton/services/graph_ql/pause_workflow_mutation.rb
273
+ - lib/zenaton/services/graph_ql/resume_workflow_mutation.rb
274
+ - lib/zenaton/services/graph_ql/send_event_mutation.rb
275
+ - lib/zenaton/services/graph_ql/workflow_query.rb
265
276
  - lib/zenaton/services/http.rb
266
277
  - lib/zenaton/services/properties.rb
267
278
  - lib/zenaton/services/serializer.rb
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'zenaton/exceptions'
4
-
5
- module Zenaton
6
- # Collection of utility classes for the Zenaton library
7
- module Services
8
- # Service that:
9
- # - handles graphql calls
10
- # - translates exceptions into Zenaton specific ones
11
- class GraphQL
12
- CREATE_WORKFLOW_SCHEDULE = <<-'GRAPHQL'
13
- mutation ($createWorkflowScheduleInput: CreateWorkflowScheduleInput!) {
14
- createWorkflowSchedule(input: $createWorkflowScheduleInput) {
15
- schedule {
16
- id
17
- }
18
- }
19
- }
20
- GRAPHQL
21
-
22
- CREATE_TASK_SCHEDULE = <<-'GRAPHQL'
23
- mutation ($createTaskScheduleInput: CreateTaskScheduleInput!) {
24
- createTaskSchedule(input: $createTaskScheduleInput) {
25
- schedule {
26
- id
27
- }
28
- }
29
- }
30
- GRAPHQL
31
-
32
- def initialize(http:)
33
- @http = http
34
- end
35
-
36
- # Makes a GRAPHQL request with some data and sets the correct headers
37
- #
38
- # @param url [String] the url for the request
39
- # @param body [Hash] the payload to send with the request
40
- # @return [Hash] the parsed json response
41
- def request(url, query, variables = nil, headers = {})
42
- body = { 'query' => query }
43
- body['variables'] = variables if variables
44
-
45
- res_body = @http.post(url, body, headers)
46
- handle_response_body(res_body)
47
- end
48
-
49
- private
50
-
51
- def handle_response_body(response_body)
52
- if external_error?(response_body)
53
- raise Zenaton::ExternalError, format_external_error(response_body)
54
- end
55
-
56
- response_body && response_body['data']
57
- end
58
-
59
- def external_error?(response_body)
60
- response_body&.key?('errors')
61
- end
62
-
63
- def format_external_error(response_body)
64
- response_body['errors'].map do |error|
65
- path = error['path'] ? "- #{error['path']}: " : ''
66
- "#{path}#{error['message']}"
67
- end.join("\n")
68
- end
69
- end
70
- end
71
- end