zenaton 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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