stepped 0.1.0 → 1.0.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 +4 -4
- data/README.md +312 -0
- data/Rakefile +6 -0
- data/app/jobs/stepped/action_job.rb +10 -0
- data/app/jobs/stepped/complete_action_job.rb +7 -0
- data/app/jobs/stepped/timeout_job.rb +11 -0
- data/app/jobs/stepped/wait_job.rb +7 -0
- data/app/models/concerns/stepped/actionable.rb +37 -0
- data/app/models/stepped/achievement.rb +25 -0
- data/app/models/stepped/action.rb +293 -0
- data/app/models/stepped/arguments.rb +15 -0
- data/app/models/stepped/definition.rb +109 -0
- data/app/models/stepped/performance.rb +76 -0
- data/app/models/stepped/registry.rb +66 -0
- data/app/models/stepped/step.rb +98 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20251214104829_create_stepped_tables_if_missing.rb +77 -0
- data/lib/stepped/engine.rb +8 -6
- data/lib/stepped/test_helper.rb +76 -0
- data/lib/stepped/version.rb +1 -3
- data/lib/stepped.rb +22 -9
- data/lib/tasks/stepped_tasks.rake +12 -0
- metadata +30 -40
- data/lib/stepped/active_record_extension.rb +0 -9
- /data/{LICENSE → MIT-LICENSE} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
class CreateSteppedTablesIfMissing < ActiveRecord::Migration[8.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :stepped_achievements, if_not_exists: true do |t|
|
|
4
|
+
t.string :checksum, null: false
|
|
5
|
+
t.string :checksum_key, null: false
|
|
6
|
+
t.timestamps null: false
|
|
7
|
+
end
|
|
8
|
+
add_index :stepped_achievements, :checksum_key, unique: true, if_not_exists: true
|
|
9
|
+
|
|
10
|
+
create_table :stepped_actions, if_not_exists: true do |t|
|
|
11
|
+
t.bigint :actor_id, null: false
|
|
12
|
+
t.string :actor_type, null: false
|
|
13
|
+
t.integer :after_callbacks_failed_count
|
|
14
|
+
t.integer :after_callbacks_succeeded_count
|
|
15
|
+
t.json :arguments
|
|
16
|
+
t.string :checksum
|
|
17
|
+
t.string :checksum_key, null: false
|
|
18
|
+
t.datetime :completed_at
|
|
19
|
+
t.string :concurrency_key, null: false
|
|
20
|
+
t.integer :current_step_index, null: false, default: 0
|
|
21
|
+
t.string :job
|
|
22
|
+
t.string :name, null: false
|
|
23
|
+
t.boolean :outbound, null: false, default: false
|
|
24
|
+
t.bigint :performance_id
|
|
25
|
+
t.boolean :root, default: false
|
|
26
|
+
t.datetime :started_at
|
|
27
|
+
t.string :status, null: false, default: "pending"
|
|
28
|
+
t.integer :timeout_seconds
|
|
29
|
+
t.timestamps null: false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
add_index :stepped_actions, %i[actor_type actor_id], name: "index_stepped_actions_on_actor", if_not_exists: true
|
|
33
|
+
add_index :stepped_actions, %i[performance_id outbound], name: "index_stepped_actions_on_performance_id_and_outbound", if_not_exists: true
|
|
34
|
+
add_index :stepped_actions, :performance_id, if_not_exists: true
|
|
35
|
+
add_index :stepped_actions, :root, if_not_exists: true
|
|
36
|
+
|
|
37
|
+
create_table :stepped_actions_steps, id: false, if_not_exists: true do |t|
|
|
38
|
+
t.bigint :action_id, null: false
|
|
39
|
+
t.bigint :step_id, null: false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
add_index :stepped_actions_steps, %i[action_id step_id], unique: true, name: "index_stepped_actions_steps_on_action_id_and_step_id", if_not_exists: true
|
|
43
|
+
add_index :stepped_actions_steps, %i[step_id action_id], name: "index_stepped_actions_steps_on_step_id_and_action_id", if_not_exists: true
|
|
44
|
+
|
|
45
|
+
create_table :stepped_performances, if_not_exists: true do |t|
|
|
46
|
+
t.bigint :action_id, null: false
|
|
47
|
+
t.string :concurrency_key
|
|
48
|
+
t.string :outbound_complete_key
|
|
49
|
+
t.timestamps null: false
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
add_index :stepped_performances, :action_id, unique: true, name: "index_stepped_performances_on_action_id", if_not_exists: true
|
|
53
|
+
add_index :stepped_performances, :concurrency_key, unique: true, name: "index_stepped_performances_on_concurrency_key", if_not_exists: true
|
|
54
|
+
add_index :stepped_performances, :outbound_complete_key,
|
|
55
|
+
name: "index_stepped_performances_on_outbound_complete_key",
|
|
56
|
+
where: "(outbound_complete_key IS NOT NULL)",
|
|
57
|
+
if_not_exists: true
|
|
58
|
+
|
|
59
|
+
create_table :stepped_steps, if_not_exists: true do |t|
|
|
60
|
+
t.bigint :action_id, null: false
|
|
61
|
+
t.datetime :completed_at
|
|
62
|
+
t.integer :definition_index, null: false
|
|
63
|
+
t.integer :pending_actions_count, null: false, default: 0
|
|
64
|
+
t.datetime :started_at
|
|
65
|
+
t.string :status, null: false, default: "pending"
|
|
66
|
+
t.integer :unsuccessful_actions_count, default: 0
|
|
67
|
+
t.timestamps null: false
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
add_index :stepped_steps, %i[action_id definition_index], unique: true, name: "index_stepped_steps_on_action_id_and_definition_index", if_not_exists: true
|
|
71
|
+
add_index :stepped_steps, :action_id, name: "index_stepped_steps_on_action_id", if_not_exists: true
|
|
72
|
+
|
|
73
|
+
add_foreign_key :stepped_actions, :stepped_performances, column: :performance_id, if_not_exists: true
|
|
74
|
+
add_foreign_key :stepped_performances, :stepped_actions, column: :action_id, if_not_exists: true
|
|
75
|
+
add_foreign_key :stepped_steps, :stepped_actions, column: :action_id, if_not_exists: true
|
|
76
|
+
end
|
|
77
|
+
end
|
data/lib/stepped/engine.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "rails/engine"
|
|
4
|
-
require "action_dispatch"
|
|
5
|
-
|
|
6
1
|
module Stepped
|
|
7
2
|
class Engine < ::Rails::Engine
|
|
8
|
-
|
|
3
|
+
config.stepped_actions = ActiveSupport::OrderedOptions.new
|
|
4
|
+
config.stepped_actions.handle_exceptions = Rails.env.test? ? [] : [ StandardError ]
|
|
5
|
+
|
|
6
|
+
initializer "stepped.active_record.extensions" do
|
|
7
|
+
ActiveSupport.on_load :active_record do
|
|
8
|
+
include Stepped::Actionable
|
|
9
|
+
end
|
|
10
|
+
end
|
|
9
11
|
end
|
|
10
12
|
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Stepped::TestHelper
|
|
2
|
+
def perform_stepped_actions(only: stepped_job_classes)
|
|
3
|
+
perform_enqueued_jobs_recursively(only:)
|
|
4
|
+
complete_stepped_outbound_performances
|
|
5
|
+
|
|
6
|
+
perform_stepped_actions(only:) if Stepped::Performance.any? || enqueued_jobs_with(only:).count > 0
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def assert_stepped_action_job(name, actor = nil)
|
|
10
|
+
jobs_before = enqueued_jobs + performed_jobs
|
|
11
|
+
yield
|
|
12
|
+
jobs = (enqueued_jobs + performed_jobs) - jobs_before
|
|
13
|
+
found = false
|
|
14
|
+
all_actions = []
|
|
15
|
+
jobs.each do |job|
|
|
16
|
+
next unless job["job_class"] == "Stepped::ActionJob"
|
|
17
|
+
|
|
18
|
+
job_actor, job_action_name = ActiveJob::Arguments.deserialize job["arguments"]
|
|
19
|
+
all_actions << [ job_actor.to_global_id, job_action_name ].join("#")
|
|
20
|
+
next if found
|
|
21
|
+
|
|
22
|
+
found = job_action_name == name
|
|
23
|
+
if found && actor.present?
|
|
24
|
+
actor = eval(actor) if actor.is_a?(String)
|
|
25
|
+
found = job_actor == actor
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
assert found, <<~MESSAGE
|
|
29
|
+
Stepped action job for '#{name}' was not enqueued or performed#{actor.respond_to?(:to_debug_id) ? " on #{actor.to_debug_id}" : nil}.
|
|
30
|
+
Actions that were: #{all_actions.join(", ")}
|
|
31
|
+
MESSAGE
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def assert_no_stepped_actions
|
|
35
|
+
jobs_before = enqueued_jobs + performed_jobs
|
|
36
|
+
yield
|
|
37
|
+
jobs = (enqueued_jobs + performed_jobs) - jobs_before
|
|
38
|
+
found = false
|
|
39
|
+
all_actions = []
|
|
40
|
+
jobs.each do |job|
|
|
41
|
+
next unless job["job_class"] == "Stepped::ActionJob"
|
|
42
|
+
found = true
|
|
43
|
+
job_actor, job_action_name = ActiveJob::Arguments.deserialize job["arguments"]
|
|
44
|
+
all_actions << [ job_actor.class.name, job_action_name ].join("#")
|
|
45
|
+
end
|
|
46
|
+
assert_not found, <<~MESSAGE
|
|
47
|
+
Stepped action jobs enqueued or performed: #{all_actions.join(", ")}
|
|
48
|
+
MESSAGE
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def handle_stepped_action_exceptions(only: [ StandardError ])
|
|
52
|
+
was = Stepped::Engine.config.stepped_actions.handle_exceptions
|
|
53
|
+
Stepped::Engine.config.stepped_actions.handle_exceptions = Array(only)
|
|
54
|
+
yield
|
|
55
|
+
ensure
|
|
56
|
+
Stepped::Engine.config.stepped_actions.handle_exceptions = was
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def perform_enqueued_jobs_recursively(only: nil)
|
|
60
|
+
total = 0
|
|
61
|
+
loop do
|
|
62
|
+
batch = perform_enqueued_jobs(only:)
|
|
63
|
+
break if batch == 0
|
|
64
|
+
total += batch
|
|
65
|
+
end
|
|
66
|
+
total
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def stepped_job_classes
|
|
70
|
+
[ Stepped::ActionJob, Stepped::TimeoutJob, Stepped::WaitJob ] + Stepped::Registry.job_classes
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def complete_stepped_outbound_performances
|
|
74
|
+
# Consuming app can redefine
|
|
75
|
+
end
|
|
76
|
+
end
|
data/lib/stepped/version.rb
CHANGED
data/lib/stepped.rb
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require "active_support/lazy_load_hooks"
|
|
4
|
-
require_relative "stepped/version"
|
|
5
|
-
require_relative "stepped/active_record_extension"
|
|
6
|
-
require_relative "stepped/engine"
|
|
1
|
+
require "stepped/version"
|
|
2
|
+
require "stepped/engine"
|
|
7
3
|
|
|
8
4
|
module Stepped
|
|
9
|
-
|
|
5
|
+
def self.table_name_prefix
|
|
6
|
+
"stepped_"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.handled_exception_classes
|
|
10
|
+
Array(Stepped::Engine.config.stepped_actions.handle_exceptions)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.handle_exception(context: {})
|
|
14
|
+
yield
|
|
15
|
+
true
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
raise unless handled_exception_classes.any? { e.class <= _1 }
|
|
18
|
+
Rails.error.report(e, handled: false, context:)
|
|
19
|
+
false
|
|
20
|
+
end
|
|
10
21
|
|
|
11
|
-
|
|
12
|
-
|
|
22
|
+
def self.checksum(value)
|
|
23
|
+
return if value.nil?
|
|
24
|
+
Digest::SHA256.hexdigest JSON.dump(value)
|
|
25
|
+
end
|
|
13
26
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
namespace :stepped do
|
|
2
|
+
desc "Install Stepped Actions"
|
|
3
|
+
task install: "stepped:install:migrations"
|
|
4
|
+
|
|
5
|
+
namespace :install do
|
|
6
|
+
desc "Copy Stepped migrations to the host app"
|
|
7
|
+
task migrations: :environment do
|
|
8
|
+
ENV["FROM"] = Stepped::Engine.railtie_name
|
|
9
|
+
Rake::Task["railties:install:migrations"].invoke
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stepped
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Starsi
|
|
@@ -15,72 +15,62 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: 8.1.1
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
25
|
+
version: 8.1.1
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
|
-
name:
|
|
27
|
+
name: temping
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '
|
|
32
|
+
version: '0'
|
|
33
33
|
type: :development
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '
|
|
40
|
-
- !ruby/object:Gem::Dependency
|
|
41
|
-
name: minitest
|
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
|
43
|
-
requirements:
|
|
44
|
-
- - ">="
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: '5.0'
|
|
47
|
-
type: :development
|
|
48
|
-
prerelease: false
|
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
-
requirements:
|
|
51
|
-
- - ">="
|
|
52
|
-
- !ruby/object:Gem::Version
|
|
53
|
-
version: '5.0'
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: rake
|
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - ">="
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: '13.0'
|
|
61
|
-
type: :development
|
|
62
|
-
prerelease: false
|
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - ">="
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: '13.0'
|
|
39
|
+
version: '0'
|
|
68
40
|
email:
|
|
69
41
|
- klevo@klevo.sk
|
|
70
42
|
executables: []
|
|
71
43
|
extensions: []
|
|
72
44
|
extra_rdoc_files: []
|
|
73
45
|
files:
|
|
74
|
-
- LICENSE
|
|
46
|
+
- MIT-LICENSE
|
|
75
47
|
- README.md
|
|
48
|
+
- Rakefile
|
|
49
|
+
- app/jobs/stepped/action_job.rb
|
|
50
|
+
- app/jobs/stepped/complete_action_job.rb
|
|
51
|
+
- app/jobs/stepped/timeout_job.rb
|
|
52
|
+
- app/jobs/stepped/wait_job.rb
|
|
53
|
+
- app/models/concerns/stepped/actionable.rb
|
|
54
|
+
- app/models/stepped/achievement.rb
|
|
55
|
+
- app/models/stepped/action.rb
|
|
56
|
+
- app/models/stepped/arguments.rb
|
|
57
|
+
- app/models/stepped/definition.rb
|
|
58
|
+
- app/models/stepped/performance.rb
|
|
59
|
+
- app/models/stepped/registry.rb
|
|
60
|
+
- app/models/stepped/step.rb
|
|
61
|
+
- config/routes.rb
|
|
62
|
+
- db/migrate/20251214104829_create_stepped_tables_if_missing.rb
|
|
76
63
|
- lib/stepped.rb
|
|
77
|
-
- lib/stepped/active_record_extension.rb
|
|
78
64
|
- lib/stepped/engine.rb
|
|
65
|
+
- lib/stepped/test_helper.rb
|
|
79
66
|
- lib/stepped/version.rb
|
|
67
|
+
- lib/tasks/stepped_tasks.rake
|
|
80
68
|
homepage: https://github.com/envirobly/stepped
|
|
81
69
|
licenses:
|
|
82
70
|
- MIT
|
|
83
|
-
metadata:
|
|
71
|
+
metadata:
|
|
72
|
+
homepage_uri: https://github.com/envirobly/stepped
|
|
73
|
+
source_code_uri: https://github.com/envirobly/stepped
|
|
84
74
|
rdoc_options: []
|
|
85
75
|
require_paths:
|
|
86
76
|
- lib
|
|
@@ -88,14 +78,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
88
78
|
requirements:
|
|
89
79
|
- - ">="
|
|
90
80
|
- !ruby/object:Gem::Version
|
|
91
|
-
version: '
|
|
81
|
+
version: '0'
|
|
92
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
83
|
requirements:
|
|
94
84
|
- - ">="
|
|
95
85
|
- !ruby/object:Gem::Version
|
|
96
86
|
version: '0'
|
|
97
87
|
requirements: []
|
|
98
|
-
rubygems_version: 4.0.
|
|
88
|
+
rubygems_version: 4.0.1
|
|
99
89
|
specification_version: 4
|
|
100
|
-
summary:
|
|
90
|
+
summary: Rails engine for orchestrating complex action trees.
|
|
101
91
|
test_files: []
|
/data/{LICENSE → MIT-LICENSE}
RENAMED
|
File without changes
|