phronomy 0.18.0 → 0.19.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/CHANGELOG.md +25 -0
- data/README.md +2 -0
- data/docs/decisions/009-state-store-abstraction.md +1 -1
- data/docs/decisions/014-unified-persistence-durable-state.md +268 -0
- data/docs/features.md +7 -1
- data/docs/getting-started.md +37 -1
- data/docs/migrations/0.19.md +148 -0
- data/docs/runtime-and-concurrency.md +93 -2
- data/lib/phronomy/agent/base.rb +81 -36
- data/lib/phronomy/agent/context_assembler.rb +13 -3
- data/lib/phronomy/agent/execution_coordinator.rb +420 -249
- data/lib/phronomy/agent/journal_projection.rb +5 -1
- data/lib/phronomy/configuration.rb +2 -1
- data/lib/phronomy/engine/event_loop.rb +86 -8
- data/lib/phronomy/engine/fsm_session.rb +6 -4
- data/lib/phronomy/engine/runtime.rb +7 -0
- data/lib/phronomy/persistence/in_memory.rb +113 -8
- data/lib/phronomy/persistence.rb +12 -3
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow.rb +10 -9
- data/lib/phronomy/workflow_runner.rb +361 -95
- data/lib/phronomy.rb +3 -0
- metadata +4 -4
- data/lib/phronomy/state_store/base.rb +0 -48
- data/lib/phronomy/state_store/in_memory.rb +0 -62
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module StateStore
|
|
5
|
-
# Abstract base class for workflow state persistence backends.
|
|
6
|
-
#
|
|
7
|
-
# Subclasses must implement {#load}, {#save}, and {#delete}.
|
|
8
|
-
# A snapshot is a plain +Hash+ with two keys:
|
|
9
|
-
# +:fields+ — output of +context.to_h+
|
|
10
|
-
# +:phase+ — +context.phase.to_s+
|
|
11
|
-
#
|
|
12
|
-
# @example Implementing a custom backend
|
|
13
|
-
# class MyStore < Phronomy::StateStore::Base
|
|
14
|
-
# def load(thread_id) = MyRecord.find_by(thread_id:)&.to_h
|
|
15
|
-
# def save(thread_id, snapshot) = MyRecord.upsert(thread_id:, data: snapshot)
|
|
16
|
-
# def delete(thread_id) = MyRecord.where(thread_id:).delete_all
|
|
17
|
-
# end
|
|
18
|
-
class Base
|
|
19
|
-
# Load the stored snapshot for +thread_id+.
|
|
20
|
-
#
|
|
21
|
-
# @param thread_id [String]
|
|
22
|
-
# @return [Hash, nil] stored snapshot hash, or +nil+ if absent
|
|
23
|
-
# @api public
|
|
24
|
-
def load(thread_id)
|
|
25
|
-
raise NotImplementedError, "#{self.class}#load is not implemented"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Persist +snapshot+ for +thread_id+. Overwrites any existing snapshot.
|
|
29
|
-
#
|
|
30
|
-
# @param thread_id [String]
|
|
31
|
-
# @param snapshot [Hash] serialisable hash of workflow state
|
|
32
|
-
# @return [void]
|
|
33
|
-
# @api public
|
|
34
|
-
def save(thread_id, snapshot)
|
|
35
|
-
raise NotImplementedError, "#{self.class}#save is not implemented"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Delete the stored snapshot for +thread_id+. No-op if absent.
|
|
39
|
-
#
|
|
40
|
-
# @param thread_id [String]
|
|
41
|
-
# @return [void]
|
|
42
|
-
# @api public
|
|
43
|
-
def delete(thread_id)
|
|
44
|
-
raise NotImplementedError, "#{self.class}#delete is not implemented"
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module StateStore
|
|
5
|
-
# Thread-safe in-process state store backed by a plain Ruby Hash.
|
|
6
|
-
#
|
|
7
|
-
# Used as the recommended default for single-process applications and tests.
|
|
8
|
-
# State does not survive process restart.
|
|
9
|
-
#
|
|
10
|
-
# @example
|
|
11
|
-
# store = Phronomy::StateStore::InMemory.new
|
|
12
|
-
# store.save("t1", { fields: { count: 1 }, phase: "__end__" })
|
|
13
|
-
# store.load("t1") # => { fields: { count: 1 }, phase: "__end__" }
|
|
14
|
-
# store.delete("t1")
|
|
15
|
-
# store.load("t1") # => nil
|
|
16
|
-
class InMemory < Base
|
|
17
|
-
def initialize
|
|
18
|
-
@data = {}
|
|
19
|
-
@mutex = Mutex.new
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# @param thread_id [String]
|
|
23
|
-
# @return [Hash, nil]
|
|
24
|
-
# @api public
|
|
25
|
-
def load(thread_id)
|
|
26
|
-
@mutex.synchronize do
|
|
27
|
-
snap = @data[thread_id]
|
|
28
|
-
snap ? deep_dup(snap) : nil
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# @param thread_id [String]
|
|
33
|
-
# @param snapshot [Hash]
|
|
34
|
-
# @return [void]
|
|
35
|
-
# @api public
|
|
36
|
-
def save(thread_id, snapshot)
|
|
37
|
-
@mutex.synchronize { @data[thread_id] = deep_dup(snapshot) }
|
|
38
|
-
nil
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# @param thread_id [String]
|
|
42
|
-
# @return [void]
|
|
43
|
-
# @api public
|
|
44
|
-
def delete(thread_id)
|
|
45
|
-
@mutex.synchronize { @data.delete(thread_id) }
|
|
46
|
-
nil
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
private
|
|
50
|
-
|
|
51
|
-
# Recursively deep-duplicates a plain-data value (Hash, Array, or scalar).
|
|
52
|
-
# Sufficient for snapshot data which consists of JSON-compatible types.
|
|
53
|
-
def deep_dup(val)
|
|
54
|
-
case val
|
|
55
|
-
when Hash then val.each_with_object({}) { |(k, v), h| h[k] = deep_dup(v) }
|
|
56
|
-
when Array then val.map { |v| deep_dup(v) }
|
|
57
|
-
else val.frozen? ? val : (val.dup rescue val) # rubocop:disable Style/RescueModifier
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|