@@ -117,46 +117,137 @@ class OutboundAdapter(_OutboundAdapter):
117117
118118
119119class BusinessService (_BusinessService ):
120- """Inbound production entry point.
120+ """Purpose:
121+ Inbound production entry point for messages entering an IoP production.
121122
122- Use for message-driven services or Python services that receive data and
123- send messages into a production. For polling services, prefer
124- PollingBusinessService. For task recipes, see
125- docs/cookbooks/add-polling-service.md and docs/cookbooks/hl7v2-native-input.md.
123+ Use when:
124+ External data, an adapter, or custom code must send a message into the
125+ production graph.
126+
127+ Lifecycle:
128+ IRIS calls on_process_input(); the default implementation delegates to
129+ on_process_input(request).
130+
131+ Best practices:
132+ Declare outbound routes with target() and wire them in a Production
133+ graph. Use PollingBusinessService for scheduled Python polling.
134+
135+ Common mistakes:
136+ Do not put startup work in __init__(); use on_init(). Do not instantiate
137+ downstream components directly.
138+
139+ Minimal example:
140+ class FileIn(BusinessService):
141+ Output = target()
142+
143+ def on_process_input(self, request):
144+ self.send_request_async(self.Output, request)
145+
146+ Related:
147+ docs/cookbooks/add-polling-service.md,
148+ docs/cookbooks/hl7v2-native-input.md
126149 """
127150
128151 pass
129152
130153
131154class PollingBusinessService (_PollingBusinessServiceMixin , BusinessService ):
132- """Scheduled inbound service called by the default IRIS inbound adapter.
155+ """Purpose:
156+ Scheduled Python service called by the default IRIS inbound adapter.
157+
158+ Use when:
159+ A production must poll an API, directory, queue, database, or other
160+ source from Python.
161+
162+ Lifecycle:
163+ IRIS calls on_process_input(); the mixin delegates that call to
164+ on_poll().
165+
166+ Best practices:
167+ Put one polling cycle in on_poll(). Declare outbound routes with
168+ target() and send messages with send_request_async(...).
169+
170+ Common mistakes:
171+ Do not block forever inside on_poll(). Do not put startup work in
172+ __init__(); use on_init().
173+
174+ Minimal example:
175+ class ApiPoller(PollingBusinessService):
176+ Output = target()
177+
178+ def on_poll(self):
179+ self.send_request_async(self.Output, MyRequest())
133180
134- Declare outbound routes with target() and send messages with
135- send_request_async(...). Do not put startup work in __init__(); use
136- on_init(). See docs/cookbooks/add-polling-service.md.
181+ Related:
182+ docs/cookbooks/add-polling-service.md
137183 """
138184
139185 pass
140186
141187
142188class BusinessOperation (_BusinessOperation ):
143- """Outbound side-effect boundary for production messages.
189+ """Purpose:
190+ Outbound side-effect boundary for production messages.
144191
145- Use operations for external APIs, file writes, database writes, FHIR
146- submission, and other side effects. Dispatch can use on_message(), typed
147- one-argument methods, or @handler(MessageType). See
148- docs/cookbooks/add-business-operation.md.
192+ Use when:
193+ A production must call an external API, write a file, update a database,
194+ submit FHIR resources, or perform another side effect.
195+
196+ Lifecycle:
197+ IRIS calls on_message(request). IoP can dispatch to @handler methods,
198+ typed one-argument methods, or the on_message fallback.
199+
200+ Best practices:
201+ Keep external-system code here. Return a response message when callers
202+ expect synchronous results.
203+
204+ Common mistakes:
205+ Do not put routing orchestration in an operation when a BusinessProcess
206+ should own the decision.
207+
208+ Minimal example:
209+ class SubmitOrder(BusinessOperation):
210+ def on_message(self, request):
211+ return SubmitResult(ok=True)
212+
213+ Related:
214+ docs/cookbooks/add-business-operation.md
149215 """
150216
151217 pass
152218
153219
154220class BusinessProcess (_BusinessProcess ):
155- """Routing, orchestration, decision, and transformation component.
221+ """Purpose:
222+ Routing, orchestration, decision, and transformation component.
223+
224+ Use when:
225+ A production needs branching, enrichment, transformation, fan-out,
226+ request/reply orchestration, or response aggregation.
156227
157- Declare outbound routes with target() and connect them in a Production
158- graph. Dispatch can use on_message(), typed one-argument methods, or
159- @handler(MessageType). See docs/cookbooks/add-business-process.md.
228+ Lifecycle:
229+ IRIS calls on_message(request). For async requests, IRIS can later call
230+ on_response(...) and on_complete(...).
231+
232+ Best practices:
233+ Declare outbound routes with target() and wire them with
234+ Production.connect(...). Use @handler(MessageType) or typed methods for
235+ multiple message types.
236+
237+ Common mistakes:
238+ Do not hard-code target component names when target() can expose a
239+ configurable route.
240+
241+ Minimal example:
242+ class Router(BusinessProcess):
243+ Accepted = target()
244+
245+ def on_message(self, request):
246+ return self.send_request_sync(self.Accepted, request)
247+
248+ Related:
249+ docs/cookbooks/add-business-process.md,
250+ docs/cookbooks/production-settings-and-targets.md
160251 """
161252
162253 pass
@@ -175,12 +266,34 @@ class DuplexProcess(_PrivateSessionProcess):
175266
176267
177268class Message (_Message ):
178- """Python-only JSON-serialized message contract.
179-
180- Use @dataclass for ordinary app messages between IoP components. Prefer
181- PersistentMessage only when IRIS needs a native persistent message body. See
182- docs/cookbooks/add-business-process.md and
183- docs/cookbooks/add-business-operation.md.
269+ """Purpose:
270+ Python-only JSON-serialized message contract.
271+
272+ Use when:
273+ IoP components exchange structured Python data and IRIS does not need a
274+ native persistent message body.
275+
276+ Lifecycle:
277+ IoP serializes dataclass fields into IOP.Message and restores the Python
278+ class on receipt.
279+
280+ Best practices:
281+ Decorate subclasses with @dataclass. Use PydanticMessage when runtime
282+ validation is more important.
283+
284+ Common mistakes:
285+ Do not use Message without @dataclass. Do not register Message classes
286+ in CLASSES; use PersistentMessage for native IRIS message bodies.
287+
288+ Minimal example:
289+ @dataclass
290+ class OrderRequest(Message):
291+ order_id: str
292+
293+ Related:
294+ docs/cookbooks/add-business-process.md,
295+ docs/cookbooks/add-business-operation.md,
296+ docs/getting-started/register-component.md
184297 """
185298
186299 pass
0 commit comments