|
1 | | -# Cookbook: Add A BusinessProcess |
2 | | - |
3 | | -## When To Use This |
4 | | - |
5 | | -Use this cookbook when a production needs routing, orchestration, decision |
6 | | -logic, enrichment, or coordination between services and operations. |
7 | | - |
8 | | -Business Processes should not own external side effects directly when a |
9 | | -Business Operation is the better boundary. Keep the process focused on deciding |
10 | | -what happens next and sending messages to downstream targets. |
11 | | - |
12 | | -## Files You Will Touch |
13 | | - |
14 | | -- the process module, such as `bp.py` or `processes.py` |
15 | | -- the message module, such as `msg.py` or `messages.py` |
16 | | -- operation modules only when downstream behavior is missing |
17 | | -- `settings.py` |
18 | | -- tests or sample payloads for routing decisions |
19 | | - |
20 | | -## Prompt To Give Your Agent |
21 | | - |
22 | | -```text |
23 | | -Add a new IoP BusinessProcess to this project. |
24 | | -
|
25 | | -Business goal: |
26 | | -<describe the routing, orchestration, enrichment, or decision logic> |
27 | | -
|
28 | | -Implementation requirements: |
29 | | -- Reuse existing message classes if they already fit. |
30 | | -- Declare outbound routes with target() attributes on the process class. |
31 | | -- Route messages with send_request_sync(), send_request_async(), or direct |
32 | | - response behavior according to the existing project pattern. |
33 | | -- Use on_message(self, request) for simple processes, or route by message type |
34 | | - with typed one-argument methods or the @handler decorator. |
35 | | -- Keep external API calls, database writes, file writes, and FHIR submission in |
36 | | - BusinessOperation classes. |
37 | | -- Do not add startup work to __init__(); use on_init() only if startup work is |
38 | | - required. |
39 | | -- Update settings.py so the process is added to the Production graph and its |
40 | | - targets are connected. |
41 | | -- Add or update tests for routing decisions. |
42 | | -- Show the exact migration and verification commands. |
43 | | -``` |
44 | | - |
45 | | -## Expected Implementation |
46 | | - |
47 | | -A process declares outbound targets and sends messages to them: |
48 | | - |
49 | | -```python |
50 | | -from iop import BusinessProcess, Message, handler, target |
51 | | - |
52 | | -from messages import OrderRequest, OrderResponse, RejectedOrder |
53 | | - |
54 | | - |
55 | | -class OrderProcess(BusinessProcess): |
56 | | - Accepted = target() |
57 | | - Rejected = target() |
58 | | - |
59 | | - def on_message(self, request): |
60 | | - self.log_warning(f"Unhandled message {type(request).__name__}") |
61 | | - return request |
62 | | - |
63 | | - def route_order(self, request: OrderRequest): |
64 | | - if not request.order_id: |
65 | | - return self.send_request_sync(self.Rejected, RejectedOrder(reason="missing id")) |
66 | | - |
67 | | - return self.send_request_sync(self.Accepted, request) |
68 | | - |
69 | | - @handler(RejectedOrder) |
70 | | - def route_rejected(self, request): |
71 | | - self.log_info(request.reason) |
72 | | - return request |
73 | | -``` |
74 | | - |
75 | | -IoP dispatches to: |
76 | | - |
77 | | -- a method decorated with `@handler(MessageType)` first |
78 | | -- a typed one-argument method such as `route_order(self, request: OrderRequest)` |
79 | | -- `on_message(self, request)` as the fallback |
80 | | - |
81 | | -Wire the process in `settings.py`: |
82 | | - |
83 | | -```python |
84 | | -process = prod.process("OrderProcess", OrderProcess) |
85 | | -accepted = prod.operation("AcceptedOperation", AcceptedOperation) |
86 | | -rejected = prod.operation("RejectedOperation", RejectedOperation) |
87 | | - |
88 | | -process.connect(OrderProcess.Accepted, accepted) |
89 | | -process.connect(OrderProcess.Rejected, rejected) |
90 | | -``` |
91 | | - |
92 | | -## Migration Command |
93 | | - |
94 | | -```bash |
95 | | -iop --migrate settings.py --dry-run |
96 | | -iop --migrate settings.py |
97 | | -``` |
98 | | - |
99 | | -## Verification |
100 | | - |
101 | | -- Unit-test the routing decision with representative messages. |
102 | | -- Dry-run migration shows the process and all target settings. |
103 | | -- The production graph contains every expected process edge. |
104 | | -- Runtime trace shows messages passing from service to process to operation. |
105 | | - |
106 | | -## Common Mistakes |
107 | | - |
108 | | -- Putting external API calls or database writes directly in the process. |
109 | | -- Forgetting `target()` declarations for outbound routes. |
110 | | -- Returning raw dictionaries instead of message objects when the downstream |
111 | | - component expects IoP messages. |
112 | | -- Adding multiple handlers for the same message type without making the |
113 | | - intended precedence explicit. |
114 | | -- Calling a downstream component directly instead of sending a production |
115 | | - message through a target. |
| 1 | +--8<-- "src/iop/ai/skills/build-iop-app/references/cookbooks/add-business-process.md" |
0 commit comments