edda-framework 0.7.0__py3-none-any.whl → 0.8.0__py3-none-any.whl

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.
edda/storage/models.py CHANGED
@@ -31,6 +31,7 @@ CREATE TABLE IF NOT EXISTS workflow_instances (
31
31
  owner_service TEXT NOT NULL,
32
32
  status TEXT NOT NULL DEFAULT 'running',
33
33
  current_activity_id TEXT,
34
+ continued_from TEXT,
34
35
  started_at TEXT NOT NULL DEFAULT (datetime('now')),
35
36
  updated_at TEXT NOT NULL DEFAULT (datetime('now')),
36
37
  input_data TEXT NOT NULL,
@@ -39,8 +40,9 @@ CREATE TABLE IF NOT EXISTS workflow_instances (
39
40
  locked_at TEXT,
40
41
  lock_timeout_seconds INTEGER,
41
42
  CONSTRAINT valid_status CHECK (
42
- status IN ('running', 'completed', 'failed', 'waiting_for_event', 'waiting_for_timer', 'compensating', 'cancelled')
43
+ status IN ('running', 'completed', 'failed', 'waiting_for_event', 'waiting_for_timer', 'waiting_for_message', 'compensating', 'cancelled', 'recurred')
43
44
  ),
45
+ FOREIGN KEY (continued_from) REFERENCES workflow_instances(instance_id),
44
46
  FOREIGN KEY (workflow_name, source_hash) REFERENCES workflow_definitions(workflow_name, source_hash)
45
47
  );
46
48
  """
@@ -53,6 +55,7 @@ WORKFLOW_INSTANCES_INDEXES = [
53
55
  "CREATE INDEX IF NOT EXISTS idx_instances_locked ON workflow_instances(locked_by, locked_at);",
54
56
  "CREATE INDEX IF NOT EXISTS idx_instances_updated ON workflow_instances(updated_at);",
55
57
  "CREATE INDEX IF NOT EXISTS idx_instances_hash ON workflow_instances(source_hash);",
58
+ "CREATE INDEX IF NOT EXISTS idx_instances_continued_from ON workflow_instances(continued_from);",
56
59
  ]
57
60
 
58
61
  # SQL schema for workflow execution history (for deterministic replay)
@@ -75,6 +78,26 @@ WORKFLOW_HISTORY_INDEXES = [
75
78
  "CREATE INDEX IF NOT EXISTS idx_history_created ON workflow_history(created_at);",
76
79
  ]
77
80
 
81
+ # SQL schema for archived workflow history (for recur pattern)
82
+ WORKFLOW_HISTORY_ARCHIVE_TABLE = """
83
+ CREATE TABLE IF NOT EXISTS workflow_history_archive (
84
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
85
+ instance_id TEXT NOT NULL,
86
+ activity_id TEXT NOT NULL,
87
+ event_type TEXT NOT NULL,
88
+ event_data TEXT NOT NULL,
89
+ created_at TEXT NOT NULL,
90
+ archived_at TEXT NOT NULL DEFAULT (datetime('now')),
91
+ FOREIGN KEY (instance_id) REFERENCES workflow_instances(instance_id) ON DELETE CASCADE
92
+ );
93
+ """
94
+
95
+ # Indexes for workflow history archive
96
+ WORKFLOW_HISTORY_ARCHIVE_INDEXES = [
97
+ "CREATE INDEX IF NOT EXISTS idx_history_archive_instance ON workflow_history_archive(instance_id);",
98
+ "CREATE INDEX IF NOT EXISTS idx_history_archive_archived ON workflow_history_archive(archived_at);",
99
+ ]
100
+
78
101
  # SQL schema for compensation transactions (LIFO stack for Saga pattern)
79
102
  WORKFLOW_COMPENSATIONS_TABLE = """
80
103
  CREATE TABLE IF NOT EXISTS workflow_compensations (
@@ -93,27 +116,6 @@ WORKFLOW_COMPENSATIONS_INDEXES = [
93
116
  "CREATE INDEX IF NOT EXISTS idx_compensations_instance ON workflow_compensations(instance_id, created_at DESC);",
94
117
  ]
95
118
 
96
- # SQL schema for event subscriptions (for wait_event)
97
- WORKFLOW_EVENT_SUBSCRIPTIONS_TABLE = """
98
- CREATE TABLE IF NOT EXISTS workflow_event_subscriptions (
99
- id INTEGER PRIMARY KEY AUTOINCREMENT,
100
- instance_id TEXT NOT NULL,
101
- event_type TEXT NOT NULL,
102
- activity_id TEXT,
103
- timeout_at TEXT,
104
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
105
- FOREIGN KEY (instance_id) REFERENCES workflow_instances(instance_id) ON DELETE CASCADE,
106
- CONSTRAINT unique_instance_event UNIQUE (instance_id, event_type)
107
- );
108
- """
109
-
110
- # Indexes for event subscriptions
111
- WORKFLOW_EVENT_SUBSCRIPTIONS_INDEXES = [
112
- "CREATE INDEX IF NOT EXISTS idx_subscriptions_event ON workflow_event_subscriptions(event_type);",
113
- "CREATE INDEX IF NOT EXISTS idx_subscriptions_timeout ON workflow_event_subscriptions(timeout_at);",
114
- "CREATE INDEX IF NOT EXISTS idx_subscriptions_instance ON workflow_event_subscriptions(instance_id);",
115
- ]
116
-
117
119
  # SQL schema for timer subscriptions (for wait_timer)
118
120
  WORKFLOW_TIMER_SUBSCRIPTIONS_TABLE = """
119
121
  CREATE TABLE IF NOT EXISTS workflow_timer_subscriptions (
@@ -134,6 +136,131 @@ WORKFLOW_TIMER_SUBSCRIPTIONS_INDEXES = [
134
136
  "CREATE INDEX IF NOT EXISTS idx_timer_subscriptions_instance ON workflow_timer_subscriptions(instance_id);",
135
137
  ]
136
138
 
139
+ # SQL schema for message subscriptions (for wait_message)
140
+ WORKFLOW_MESSAGE_SUBSCRIPTIONS_TABLE = """
141
+ CREATE TABLE IF NOT EXISTS workflow_message_subscriptions (
142
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
143
+ instance_id TEXT NOT NULL,
144
+ channel TEXT NOT NULL,
145
+ activity_id TEXT,
146
+ timeout_at TEXT,
147
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
148
+ FOREIGN KEY (instance_id) REFERENCES workflow_instances(instance_id) ON DELETE CASCADE,
149
+ CONSTRAINT unique_instance_channel UNIQUE (instance_id, channel)
150
+ );
151
+ """
152
+
153
+ # Indexes for message subscriptions
154
+ WORKFLOW_MESSAGE_SUBSCRIPTIONS_INDEXES = [
155
+ "CREATE INDEX IF NOT EXISTS idx_message_subscriptions_channel ON workflow_message_subscriptions(channel);",
156
+ "CREATE INDEX IF NOT EXISTS idx_message_subscriptions_timeout ON workflow_message_subscriptions(timeout_at);",
157
+ "CREATE INDEX IF NOT EXISTS idx_message_subscriptions_instance ON workflow_message_subscriptions(instance_id);",
158
+ ]
159
+
160
+ # SQL schema for group memberships (Erlang pg style)
161
+ WORKFLOW_GROUP_MEMBERSHIPS_TABLE = """
162
+ CREATE TABLE IF NOT EXISTS workflow_group_memberships (
163
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
164
+ instance_id TEXT NOT NULL,
165
+ group_name TEXT NOT NULL,
166
+ joined_at TEXT NOT NULL DEFAULT (datetime('now')),
167
+ FOREIGN KEY (instance_id) REFERENCES workflow_instances(instance_id) ON DELETE CASCADE,
168
+ CONSTRAINT unique_instance_group UNIQUE (instance_id, group_name)
169
+ );
170
+ """
171
+
172
+ # Indexes for group memberships
173
+ WORKFLOW_GROUP_MEMBERSHIPS_INDEXES = [
174
+ "CREATE INDEX IF NOT EXISTS idx_group_memberships_group ON workflow_group_memberships(group_name);",
175
+ "CREATE INDEX IF NOT EXISTS idx_group_memberships_instance ON workflow_group_memberships(instance_id);",
176
+ ]
177
+
178
+ # =============================================================================
179
+ # Channel-based Message Queue System
180
+ # =============================================================================
181
+
182
+ # SQL schema for channel messages (persistent message queue)
183
+ CHANNEL_MESSAGES_TABLE = """
184
+ CREATE TABLE IF NOT EXISTS channel_messages (
185
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
186
+ channel TEXT NOT NULL,
187
+ message_id TEXT NOT NULL UNIQUE,
188
+ data_type TEXT NOT NULL,
189
+ data TEXT,
190
+ data_binary BLOB,
191
+ metadata TEXT,
192
+ published_at TEXT NOT NULL DEFAULT (datetime('now')),
193
+ CONSTRAINT valid_data_type CHECK (data_type IN ('json', 'binary')),
194
+ CONSTRAINT data_type_consistency CHECK (
195
+ (data_type = 'json' AND data IS NOT NULL AND data_binary IS NULL) OR
196
+ (data_type = 'binary' AND data IS NULL AND data_binary IS NOT NULL)
197
+ )
198
+ );
199
+ """
200
+
201
+ # Indexes for channel messages
202
+ CHANNEL_MESSAGES_INDEXES = [
203
+ "CREATE INDEX IF NOT EXISTS idx_channel_messages_channel ON channel_messages(channel, published_at);",
204
+ "CREATE INDEX IF NOT EXISTS idx_channel_messages_id ON channel_messages(id);",
205
+ ]
206
+
207
+ # SQL schema for channel subscriptions
208
+ CHANNEL_SUBSCRIPTIONS_TABLE = """
209
+ CREATE TABLE IF NOT EXISTS channel_subscriptions (
210
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
211
+ instance_id TEXT NOT NULL,
212
+ channel TEXT NOT NULL,
213
+ mode TEXT NOT NULL,
214
+ activity_id TEXT,
215
+ cursor_message_id INTEGER,
216
+ subscribed_at TEXT NOT NULL DEFAULT (datetime('now')),
217
+ FOREIGN KEY (instance_id) REFERENCES workflow_instances(instance_id) ON DELETE CASCADE,
218
+ CONSTRAINT valid_mode CHECK (mode IN ('broadcast', 'competing')),
219
+ CONSTRAINT unique_instance_channel UNIQUE (instance_id, channel)
220
+ );
221
+ """
222
+
223
+ # Indexes for channel subscriptions
224
+ CHANNEL_SUBSCRIPTIONS_INDEXES = [
225
+ "CREATE INDEX IF NOT EXISTS idx_channel_subscriptions_channel ON channel_subscriptions(channel);",
226
+ "CREATE INDEX IF NOT EXISTS idx_channel_subscriptions_instance ON channel_subscriptions(instance_id);",
227
+ "CREATE INDEX IF NOT EXISTS idx_channel_subscriptions_waiting ON channel_subscriptions(channel, activity_id);",
228
+ ]
229
+
230
+ # SQL schema for channel delivery cursors (broadcast mode: track who read what)
231
+ CHANNEL_DELIVERY_CURSORS_TABLE = """
232
+ CREATE TABLE IF NOT EXISTS channel_delivery_cursors (
233
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
234
+ channel TEXT NOT NULL,
235
+ instance_id TEXT NOT NULL,
236
+ last_delivered_id INTEGER NOT NULL,
237
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
238
+ FOREIGN KEY (instance_id) REFERENCES workflow_instances(instance_id) ON DELETE CASCADE,
239
+ CONSTRAINT unique_channel_instance UNIQUE (channel, instance_id)
240
+ );
241
+ """
242
+
243
+ # Indexes for channel delivery cursors
244
+ CHANNEL_DELIVERY_CURSORS_INDEXES = [
245
+ "CREATE INDEX IF NOT EXISTS idx_channel_delivery_cursors_channel ON channel_delivery_cursors(channel);",
246
+ ]
247
+
248
+ # SQL schema for channel message claims (competing mode: who is processing what)
249
+ CHANNEL_MESSAGE_CLAIMS_TABLE = """
250
+ CREATE TABLE IF NOT EXISTS channel_message_claims (
251
+ message_id TEXT PRIMARY KEY,
252
+ instance_id TEXT NOT NULL,
253
+ claimed_at TEXT NOT NULL DEFAULT (datetime('now')),
254
+ FOREIGN KEY (message_id) REFERENCES channel_messages(message_id) ON DELETE CASCADE,
255
+ FOREIGN KEY (instance_id) REFERENCES workflow_instances(instance_id) ON DELETE CASCADE
256
+ );
257
+ """
258
+
259
+ # Indexes for channel message claims
260
+ CHANNEL_MESSAGE_CLAIMS_INDEXES = [
261
+ "CREATE INDEX IF NOT EXISTS idx_channel_message_claims_instance ON channel_message_claims(instance_id);",
262
+ ]
263
+
137
264
  # SQL schema for transactional outbox pattern
138
265
  OUTBOX_EVENTS_TABLE = """
139
266
  CREATE TABLE IF NOT EXISTS outbox_events (
@@ -176,10 +303,17 @@ ALL_TABLES = [
176
303
  WORKFLOW_DEFINITIONS_TABLE,
177
304
  WORKFLOW_INSTANCES_TABLE,
178
305
  WORKFLOW_HISTORY_TABLE,
306
+ WORKFLOW_HISTORY_ARCHIVE_TABLE,
179
307
  WORKFLOW_COMPENSATIONS_TABLE,
180
- WORKFLOW_EVENT_SUBSCRIPTIONS_TABLE,
181
308
  WORKFLOW_TIMER_SUBSCRIPTIONS_TABLE,
309
+ WORKFLOW_MESSAGE_SUBSCRIPTIONS_TABLE,
310
+ WORKFLOW_GROUP_MEMBERSHIPS_TABLE,
182
311
  OUTBOX_EVENTS_TABLE,
312
+ # Channel-based Message Queue System
313
+ CHANNEL_MESSAGES_TABLE,
314
+ CHANNEL_SUBSCRIPTIONS_TABLE,
315
+ CHANNEL_DELIVERY_CURSORS_TABLE,
316
+ CHANNEL_MESSAGE_CLAIMS_TABLE,
183
317
  ]
184
318
 
185
319
  # All index creation statements
@@ -187,8 +321,15 @@ ALL_INDEXES = (
187
321
  WORKFLOW_DEFINITIONS_INDEXES
188
322
  + WORKFLOW_INSTANCES_INDEXES
189
323
  + WORKFLOW_HISTORY_INDEXES
324
+ + WORKFLOW_HISTORY_ARCHIVE_INDEXES
190
325
  + WORKFLOW_COMPENSATIONS_INDEXES
191
- + WORKFLOW_EVENT_SUBSCRIPTIONS_INDEXES
192
326
  + WORKFLOW_TIMER_SUBSCRIPTIONS_INDEXES
327
+ + WORKFLOW_MESSAGE_SUBSCRIPTIONS_INDEXES
328
+ + WORKFLOW_GROUP_MEMBERSHIPS_INDEXES
193
329
  + OUTBOX_EVENTS_INDEXES
330
+ # Channel-based Message Queue System
331
+ + CHANNEL_MESSAGES_INDEXES
332
+ + CHANNEL_SUBSCRIPTIONS_INDEXES
333
+ + CHANNEL_DELIVERY_CURSORS_INDEXES
334
+ + CHANNEL_MESSAGE_CLAIMS_INDEXES
194
335
  )