Skip to content

Commit fc1f6d7

Browse files
improvement: add transaction hooks for read actions (#2219)
* docs(actions): remove exceptions for read action hook support
1 parent cadd87f commit fc1f6d7

File tree

4 files changed

+550
-186
lines changed

4 files changed

+550
-186
lines changed

documentation/topics/actions/actions.md

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -286,20 +286,18 @@ Ash resource actions follow a well-defined lifecycle that ensures proper data va
286286
- **Transaction Phase** - Operations within database transaction
287287
- **Post-Transaction Phase** - Operations after database transaction
288288

289-
#### Important Notes:
289+
#### Important Note:
290290

291-
- **Query Actions**: Read queries do not currently have `before_transaction`, `after_transaction`, or `around_transaction` callbacks
292291
- **Around Action Behavior**: `around_action` hooks do not complete their "end" phase if the action fails
293-
- **Generic Actions**: Generic actions support validations, preparations, and all hook types including transaction-level hooks (before_transaction/after_transaction/around_transaction).
294292

295293
### Complete Lifecycle Flow
296294

297295
```mermaid
298296
graph TD
299297
subgraph "Pre-Transaction Phase"
300298
START["Action Invocation<br/>(Ash.create, Ash.read, Ash.run_action, etc.)"] --> PREP["Changeset/Query/ActionInput Creation"]
301-
PREP --> AROUND_START["around_transaction (start)<br/>🚫 Not available for read/query actions"]
302-
AROUND_START --> BEFORE_TRANS["before_transaction<br/>🚫 Not available for read/query actions"]
299+
PREP --> AROUND_START["around_transaction (start)"]
300+
AROUND_START --> BEFORE_TRANS["before_transaction"]
303301
end
304302
305303
subgraph "Transaction Phase"
@@ -334,7 +332,7 @@ graph TD
334332
end
335333
336334
subgraph "Post-Transaction Phase"
337-
AFTER_TRANS["after_transaction<br/>(Always runs - success/error)<br/>🚫 Not available for read/query actions"] --> AROUND_END["around_transaction (end)<br/>🚫 Not available for read/query actions"]
335+
AFTER_TRANS["after_transaction<br/>(Always runs - success/error)"] --> AROUND_END["around_transaction (end)"]
338336
AROUND_END --> NOTIFICATIONS["Notifications<br/>(If enabled)"]
339337
NOTIFICATIONS --> RESULT["Return Result"]
340338
end
@@ -365,7 +363,6 @@ graph TD
365363
- Resource allocation
366364
- Logging/monitoring setup
367365
- **Transaction Context**: Outside transaction
368-
- **Note**: Not available for query/read actions
369366

370367
##### 4. before_transaction
371368
- **When**: Just before transaction starts
@@ -376,7 +373,6 @@ graph TD
376373
- Cache warming
377374
- Non-transactional preparations
378375
- **Transaction Context**: Outside transaction
379-
- **Note**: Not available for query/read actions
380376

381377
#### Transaction Phase (Inside Database Transaction)
382378

@@ -489,7 +485,7 @@ graph TD
489485
- Retry mechanisms - can change error results to success
490486
- **Transaction Context**: Outside transaction
491487
- **Special Capability**: Can transform the final result (e.g., retry failed operations)
492-
- **Note**: Always runs, regardless of success/failure (not available for query/read actions)
488+
- **Note**: Always runs, regardless of success/failure
493489

494490
##### 17. around_transaction (End)
495491
- **When**: Final cleanup phase
@@ -499,7 +495,6 @@ graph TD
499495
- Final cleanup
500496
- Monitoring completion
501497
- **Transaction Context**: Outside transaction
502-
- **Note**: Not available for query/read actions
503498

504499
##### 18. Notifications
505500
- **When**: After all hooks complete
@@ -537,6 +532,8 @@ The hooks execute in the following order (as of Ash 3.0+):
537532

538533
#### For Read/Query Actions:
539534

535+
1. `around_transaction` (start)
536+
1. `before_transaction`
540537
1. Transaction begins (if applicable)
541538
1. Global preparations/validations/changes (in order of definition)
542539
1. Action preparations/validations/changes (in order of definition)
@@ -546,6 +543,8 @@ The hooks execute in the following order (as of Ash 3.0+):
546543
1. `after_action` (success only) OR Error handling
547544
1. `around_action` (end) - Only on success
548545
1. Transaction commits/rollbacks (if applicable)
546+
1. `after_transaction` (always runs - success/error)
547+
1. `around_transaction` (end)
549548

550549
#### For Generic Actions:
551550

@@ -566,13 +565,13 @@ The hooks execute in the following order (as of Ash 3.0+):
566565
### Key Points
567566

568567
#### Transaction Boundaries
569-
- **Outside Transaction**: `around_transaction`, `before_transaction`, `after_transaction` (available for create/update/destroy/generic actions)
568+
- **Outside Transaction**: `around_transaction`, `before_transaction`, `after_transaction`
570569
- **Inside Transaction**: Action preparations/validations/changes, Global preparations/validations/changes, `around_action`, `before_action`, `after_action`
571570

572571
#### Error Handling
573572
- `after_action` only runs on successful operations
574573
- `around_action` (end) only runs on successful operations
575-
- `after_transaction` always runs (success and error) - available for create/update/destroy/generic actions
574+
- `after_transaction` always runs (success and error)
576575
- `after_transaction` can change the final result - can transform errors into successes (useful for retries)
577576
- Transaction rollback occurs automatically on errors
578577

@@ -592,29 +591,24 @@ The hooks execute in the following order (as of Ash 3.0+):
592591
### Action Type Differences
593592

594593
#### Create/Update/Destroy Actions
595-
- Have full lifecycle including all transaction hooks
596-
- Support `before_transaction`, `after_transaction`, `around_transaction`
597594
- Run in transactions by default, unless no hooks of any kind are added to the changeset.
598595
- Have complete error handling and rollback capabilities
599596

600597
#### Read/Query Actions
601-
- Do not support `before_transaction`, `after_transaction`, or `around_transaction` hooks
602-
- Only support `before_action`, `after_action`, and `around_action` hooks
603598
- Do not run in transactions by default
604599
- Focus on data retrieval and filtering
605600

606601
#### Generic Actions
607-
- Support validations, preparations, and all hook types (`before_action`, `after_action`, `around_action`, `before_transaction`, `after_transaction`, `around_transaction`)
602+
- Support validations, preparations, and all hook types
608603
- Can run in transactions by setting `transaction? true` in the action definition
609-
- Transaction hooks work for both transactional and non-transactional generic actions
610604
- Focus on custom business logic and operations
611605

612606
### Best Practices
613607

614-
- Use `before_transaction` for external API calls (create/update/destroy/generic actions only)
608+
- Use `before_transaction` for external API calls
615609
- Use `before_action` for final data modifications
616610
- Use `after_action` for transactional side effects
617-
- Use `after_transaction` for external notifications (create/update/destroy/generic actions only)
611+
- Use `after_transaction` for external notifications
618612
- Use `after_transaction` for retry mechanisms and result transformation
619613
- Keep transaction phase operations fast and focused
620614
- Handle errors appropriately at each phase

0 commit comments

Comments
 (0)