Class: InstallSagaForge

Inherits:
Object
  • Object
show all
Defined in:
lib/generators/saga_forge/templates/install_saga_forge.rb

Instance Method Summary collapse

Instance Method Details

#changeObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/generators/saga_forge/templates/install_saga_forge.rb', line 4

def change
  create_table :saga_forge_states, id: primary_key_type do |t|
    t.string :saga_class, null: false
    t.string :correlation_id, null: false
    t.string :current_state, null: false
    t.integer :version, null: false, default: 0

    if t.respond_to?(:jsonb)
      t.jsonb :context, null: false, default: {}
    else
      t.json :context, null: false, default: {}
    end

    t.datetime :finalized_at
    t.datetime :last_active_at

    t.timestamps

    t.index %i[saga_class correlation_id], unique: true
    t.index %i[saga_class current_state]
    # Plain (non-partial, adapter-portable) index: the sweeper's stranded-
    # compensating scan filters current_state cross-class, which neither
    # of the above compound indexes serves.
    t.index :current_state
    # Retention/dashboard filter finalized vs active in SQL (finalized_at
    # IS [NOT] NULL) without loading each saga class to ask terminal?.
    t.index :finalized_at
  end

  create_table :saga_forge_events, id: primary_key_type do |t|
    t.string :saga_class, null: false
    t.string :correlation_id, null: false
    # Lone-column index on saga_forge_state_id intentionally omitted:
    # the [saga_forge_state_id, created_at] index below covers left-prefix lookups.
    t.references :saga_forge_state, type: foreign_key_type,
      foreign_key: {to_table: :saga_forge_states}, index: false

    t.string :event_name, null: false
    t.integer :status, null: false, default: 0
    t.integer :stall_count, null: false, default: 0
    t.integer :attempts, null: false, default: 0
    t.datetime :last_processed_at

    if t.respond_to?(:jsonb)
      t.jsonb :payload, null: false, default: {}
      t.jsonb :retry_budgets, null: false, default: {}
      t.jsonb :error
    else
      t.json :payload, null: false, default: {}
      t.json :retry_budgets, null: false, default: {}
      t.json :error
    end

    t.timestamps

    # Structural idempotency: a saga instance handles each event name at
    # most once (forward-only, no stay), so this tuple IS the dedup key —
    # webhook redeliveries and saga-to-saga fan-in no-op at the index.
    t.index %i[saga_class correlation_id event_name], unique: true
    t.index %i[saga_class correlation_id status]
    t.index %i[status created_at]
    t.index %i[saga_forge_state_id created_at]
  end
end