zenaton 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +79 -52
- data/.gitignore +7 -0
- data/.rubocop.yml +4 -0
- data/Appraisals +13 -0
- data/CHANGELOG.md +17 -1
- data/Gemfile.lock +17 -8
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/rails_5.0.gemfile +7 -0
- data/gemfiles/rails_5.1.gemfile +7 -0
- data/gemfiles/rails_5.2.gemfile +7 -0
- data/lib/zenaton/client.rb +63 -0
- data/lib/zenaton/contexts.rb +7 -0
- data/lib/zenaton/contexts/task.rb +33 -0
- data/lib/zenaton/contexts/workflow.rb +17 -0
- data/lib/zenaton/engine.rb +16 -0
- data/lib/zenaton/interfaces/task.rb +30 -1
- data/lib/zenaton/interfaces/workflow.rb +15 -0
- data/lib/zenaton/refinements.rb +16 -0
- data/lib/zenaton/refinements/big_decimal.rb +25 -0
- data/lib/zenaton/refinements/class.rb +21 -0
- data/lib/zenaton/refinements/complex.rb +22 -0
- data/lib/zenaton/refinements/date.rb +26 -0
- data/lib/zenaton/refinements/date_time.rb +40 -0
- data/lib/zenaton/refinements/exception.rb +24 -0
- data/lib/zenaton/refinements/object.rb +15 -0
- data/lib/zenaton/refinements/open_struct.rb +26 -0
- data/lib/zenaton/refinements/range.rb +21 -0
- data/lib/zenaton/refinements/rational.rb +22 -0
- data/lib/zenaton/refinements/regexp.rb +22 -0
- data/lib/zenaton/refinements/struct.rb +24 -0
- data/lib/zenaton/refinements/symbol.rb +21 -0
- data/lib/zenaton/refinements/time.rb +32 -0
- data/lib/zenaton/services/graphql.rb +71 -0
- data/lib/zenaton/services/http.rb +14 -9
- data/lib/zenaton/services/properties.rb +11 -57
- data/lib/zenaton/services/serializer.rb +2 -0
- data/lib/zenaton/traits/with_timestamp.rb +4 -2
- data/lib/zenaton/traits/zenatonable.rb +9 -0
- data/lib/zenaton/version.rb +1 -1
- data/zenaton.gemspec +2 -0
- metadata +54 -2
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zenaton
|
4
|
+
module Contexts
|
5
|
+
# Represents the current runtime context of a Task.
|
6
|
+
#
|
7
|
+
# The information provided by the context can be useful to alter the
|
8
|
+
# behaviour of the task.
|
9
|
+
#
|
10
|
+
# For example, you can use the attempt index to know if a task has been
|
11
|
+
# automatically retried or not and how many times, and decide to do
|
12
|
+
# something when you did not expect the task to be retried more than X
|
13
|
+
# times.
|
14
|
+
#
|
15
|
+
# You can also use the attempt number in the `on_error_retry_delay` method
|
16
|
+
# of a task in order to implement complex retry strategies.
|
17
|
+
class Task
|
18
|
+
# @return [String] The UUID identifying the current task
|
19
|
+
attr_reader :id
|
20
|
+
|
21
|
+
# @return [Integer] The number of times this task has been automatically
|
22
|
+
# retried. This counter is reset if you issue a manual retry from your
|
23
|
+
# dashboard
|
24
|
+
attr_reader :retry_index
|
25
|
+
|
26
|
+
# @return [Zenaton::Contexts::Task] a new execution context for a task
|
27
|
+
def initialize(**kwargs)
|
28
|
+
@id = kwargs[:id]
|
29
|
+
@retry_index = kwargs[:retry_index]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zenaton
|
4
|
+
module Contexts
|
5
|
+
# Represents the current runtime context of a Workflow.
|
6
|
+
class Workflow
|
7
|
+
# @return [String] The UUID identifying the current workflow
|
8
|
+
attr_reader :id
|
9
|
+
|
10
|
+
# @return [Zenaton::Contexts::Workflow] a new execution context for a
|
11
|
+
# workflow
|
12
|
+
def initialize(**kwargs)
|
13
|
+
@id = kwargs[:id]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/zenaton/engine.rb
CHANGED
@@ -24,6 +24,22 @@ module Zenaton
|
|
24
24
|
@processor = nil
|
25
25
|
end
|
26
26
|
|
27
|
+
# Executes scheduling jobs synchronously
|
28
|
+
# @param jobs [Array<Zenaton::Interfaces::Job>]
|
29
|
+
# @param cron String
|
30
|
+
# @return [Array<String>, nil] the results if executed locally, or nil
|
31
|
+
def schedule(jobs, cron)
|
32
|
+
jobs.map(&method(:check_argument))
|
33
|
+
jobs.map do |job|
|
34
|
+
if job.is_a? Interfaces::Workflow
|
35
|
+
@client.start_scheduled_workflow(job, cron)
|
36
|
+
else
|
37
|
+
@client.start_scheduled_task(job, cron)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
27
43
|
# Executes jobs synchronously
|
28
44
|
# @param jobs [Array<Zenaton::Interfaces::Job>]
|
29
45
|
# @return [Array<String>, nil] the results if executed locally, or nil
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'zenaton/interfaces/job'
|
4
|
+
require 'zenaton/contexts/task'
|
4
5
|
|
5
6
|
module Zenaton
|
6
7
|
module Interfaces
|
@@ -9,7 +10,35 @@ module Zenaton
|
|
9
10
|
# Child classes should implement the handle method
|
10
11
|
def handle
|
11
12
|
raise NotImplemented,
|
12
|
-
"Your workflow does not implement the
|
13
|
+
"Your workflow does not implement the `#handle' method"
|
14
|
+
end
|
15
|
+
|
16
|
+
# (Optional) Implement this method for automatic retrial of task in
|
17
|
+
# case of failures.
|
18
|
+
# @param _exception [Exception] the reason for the task failure.
|
19
|
+
# @return [Integer, FalseClass, NilClass] the non-negative amount of
|
20
|
+
# seconds to wait before automatically retrying this task. Falsy values
|
21
|
+
# will avoid retrial. Other values will cause the retrial to fail.
|
22
|
+
def on_error_retry_delay(_exception)
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Zenaton::Contexts::Task] the task execution context
|
27
|
+
def context
|
28
|
+
@context || Contexts::Task.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# @private
|
32
|
+
# Sets a new context if none has been set yet.
|
33
|
+
# This is called from the zenaton agent and will raise if called twice.
|
34
|
+
# @raise [ArgumentError] when the context was already set.
|
35
|
+
def add_context(**attributes)
|
36
|
+
message = <<~ERROR
|
37
|
+
Context has already been set and cannot be mutated.
|
38
|
+
ERROR
|
39
|
+
raise ArgumentError, message if @context
|
40
|
+
|
41
|
+
@context = Contexts::Task.new(attributes)
|
13
42
|
end
|
14
43
|
end
|
15
44
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'zenaton/interfaces/job'
|
4
|
+
require 'zenaton/contexts/workflow'
|
4
5
|
|
5
6
|
module Zenaton
|
6
7
|
module Interfaces
|
@@ -18,6 +19,20 @@ module Zenaton
|
|
18
19
|
def id
|
19
20
|
nil
|
20
21
|
end
|
22
|
+
|
23
|
+
# @return [Zenaton::Contexts::Workflow] the workflow execution context
|
24
|
+
def context
|
25
|
+
@context || Contexts::Workflow.new
|
26
|
+
end
|
27
|
+
|
28
|
+
# @private
|
29
|
+
# Sets a new context if none has been set yet.
|
30
|
+
# This is called from the zenaton agent and will raise if called twice.
|
31
|
+
# @raise [ArgumentError] when the context was already set.
|
32
|
+
def add_context(**attributes)
|
33
|
+
raise ArgumentError if @context
|
34
|
+
@context = Contexts::Workflow.new(attributes)
|
35
|
+
end
|
21
36
|
end
|
22
37
|
end
|
23
38
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zenaton/refinements/big_decimal'
|
4
|
+
require 'zenaton/refinements/class'
|
5
|
+
require 'zenaton/refinements/complex'
|
6
|
+
require 'zenaton/refinements/date'
|
7
|
+
require 'zenaton/refinements/date_time'
|
8
|
+
require 'zenaton/refinements/exception'
|
9
|
+
require 'zenaton/refinements/object'
|
10
|
+
require 'zenaton/refinements/open_struct'
|
11
|
+
require 'zenaton/refinements/range'
|
12
|
+
require 'zenaton/refinements/rational'
|
13
|
+
require 'zenaton/refinements/regexp'
|
14
|
+
require 'zenaton/refinements/struct'
|
15
|
+
require 'zenaton/refinements/symbol'
|
16
|
+
require 'zenaton/refinements/time'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Style/AndOr
|
4
|
+
defined?(::BigDecimal) or require 'bigdecimal'
|
5
|
+
# rubocop:enable Style/AndOr
|
6
|
+
|
7
|
+
module Zenaton
|
8
|
+
# :nodoc
|
9
|
+
module Refinements
|
10
|
+
refine BigDecimal do
|
11
|
+
def to_zenaton
|
12
|
+
{
|
13
|
+
'b' => _dump
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Reimplements `json/add/bigdecimal`
|
21
|
+
class BigDecimal
|
22
|
+
def self.from_zenaton(props)
|
23
|
+
BigDecimal._load props['b']
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zenaton
|
4
|
+
# :nodoc
|
5
|
+
module Refinements
|
6
|
+
refine Class do
|
7
|
+
def to_zenaton
|
8
|
+
{
|
9
|
+
'n' => name
|
10
|
+
}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Load an instance of class from zenaton properties
|
17
|
+
class Class
|
18
|
+
def self.from_zenaton(props)
|
19
|
+
Object.const_get(props['n'])
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zenaton
|
4
|
+
# :nodoc
|
5
|
+
module Refinements
|
6
|
+
refine Complex do
|
7
|
+
def to_zenaton
|
8
|
+
{
|
9
|
+
'r' => real,
|
10
|
+
'i' => imag
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Reimplements `json/add/complex`
|
18
|
+
class Complex
|
19
|
+
def self.from_zenaton(props)
|
20
|
+
Complex(props['r'], props['i'])
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
module Zenaton
|
6
|
+
# :nodoc
|
7
|
+
module Refinements
|
8
|
+
refine Date do
|
9
|
+
def to_zenaton
|
10
|
+
{
|
11
|
+
'y' => year,
|
12
|
+
'm' => month,
|
13
|
+
'd' => day,
|
14
|
+
'sg' => start
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Reimplements `json/add/date`
|
22
|
+
class Date
|
23
|
+
def self.from_zenaton(props)
|
24
|
+
civil(*props.values_at('y', 'm', 'd', 'sg'))
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
module Zenaton
|
6
|
+
# :nodoc
|
7
|
+
module Refinements
|
8
|
+
refine DateTime do
|
9
|
+
def to_zenaton
|
10
|
+
{
|
11
|
+
'y' => year,
|
12
|
+
'm' => month,
|
13
|
+
'd' => day,
|
14
|
+
'H' => hour,
|
15
|
+
'M' => min,
|
16
|
+
'S' => sec,
|
17
|
+
'of' => offset.to_s,
|
18
|
+
'sg' => start
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Reimplements `json/add/date_time`
|
26
|
+
class DateTime
|
27
|
+
def self.from_zenaton(props)
|
28
|
+
args = props.values_at('y', 'm', 'd', 'H', 'M', 'S')
|
29
|
+
of_a, of_b = props['of'].split('/')
|
30
|
+
# rubocop:disable Style/ConditionalAssignment
|
31
|
+
if of_b && of_b != '0'
|
32
|
+
args << Rational(of_a.to_i, of_b.to_i)
|
33
|
+
else
|
34
|
+
args << of_a
|
35
|
+
end
|
36
|
+
# rubocop:enable Style/ConditionalAssignment
|
37
|
+
args << props['sg']
|
38
|
+
civil(*args)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zenaton
|
4
|
+
# :nodoc
|
5
|
+
module Refinements
|
6
|
+
refine Exception do
|
7
|
+
def to_zenaton
|
8
|
+
{
|
9
|
+
'm' => message,
|
10
|
+
'b' => backtrace
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Reimplements `json/add/exception`
|
18
|
+
class Exception
|
19
|
+
def self.from_zenaton(props)
|
20
|
+
result = new(props['m'])
|
21
|
+
result.set_backtrace props['b']
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module Zenaton
|
6
|
+
# :nodoc
|
7
|
+
module Refinements
|
8
|
+
refine OpenStruct do
|
9
|
+
def to_zenaton
|
10
|
+
class_name = self.class.name.to_s
|
11
|
+
error_message = 'Only named structs are supported'
|
12
|
+
raise ArgumentError, error_message if class_name.empty?
|
13
|
+
{
|
14
|
+
't' => table
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Reimplements `json/add/ostruct`
|
22
|
+
class OpenStruct
|
23
|
+
def self.from_zenaton(props)
|
24
|
+
new(props['t'] || props[:t])
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zenaton
|
4
|
+
# :nodoc
|
5
|
+
module Refinements
|
6
|
+
refine Range do
|
7
|
+
def to_zenaton
|
8
|
+
{
|
9
|
+
'a' => [first, last, exclude_end?]
|
10
|
+
}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Reimplements `json/add/range`
|
17
|
+
class Range
|
18
|
+
def self.from_zenaton(props)
|
19
|
+
new(*props['a'])
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zenaton
|
4
|
+
# :nodoc
|
5
|
+
module Refinements
|
6
|
+
refine Rational do
|
7
|
+
def to_zenaton
|
8
|
+
{
|
9
|
+
'n' => numerator,
|
10
|
+
'd' => denominator
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Reimplements `json/add/rational`
|
18
|
+
class Rational
|
19
|
+
def self.from_zenaton(props)
|
20
|
+
Rational(props['n'], props['d'])
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zenaton
|
4
|
+
# :nodoc
|
5
|
+
module Refinements
|
6
|
+
refine Regexp do
|
7
|
+
def to_zenaton
|
8
|
+
{
|
9
|
+
'o' => options,
|
10
|
+
's' => source
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Reimplements `json/add/regexp`
|
18
|
+
class Regexp
|
19
|
+
def self.from_zenaton(props)
|
20
|
+
new(props['s'], props['o'])
|
21
|
+
end
|
22
|
+
end
|