Skip to content

Commit ad60ed0

Browse files
committed
Update CHANGELOG and add component interaction documentation with new generator request method
1 parent 763e761 commit ad60ed0

File tree

4 files changed

+314
-5
lines changed

4 files changed

+314
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
## [unreleased] - Unreleased
1010
### Added
1111
- Initial support for venv
12+
- New `send_generator_request` method in `iop` module to send generator requests
1213

1314
## [3.4.4] - 2025-06-13
1415
### Added

demo/python/generator/bo.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
from typing import Any
22
from iop import BusinessOperation
33

4-
from msg import MyGeneratorResponse, MyGenerator # Import the generator message class
4+
from msg import MyGeneratorResponse, MyGenerator
55

66
class MyGeneratorOperation(BusinessOperation):
77

8-
def on_other_request(self, request: MyGeneratorResponse) -> Any:
9-
self.log_info("Received other request")
10-
return MyGeneratorResponse(my_other_string="Hello, World!")
11-
128
def on_private_session_started(self, request: MyGenerator) -> Any:
139
self.log_info("Private session started")
1410
return self.my_generator(request)

docs/component-interation.md

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
# Component Interaction
2+
3+
This is the IRIS Framework.
4+
5+
![IRIS Framework](./img/FrameworkFull.png)
6+
7+
The components inside of IRIS represent a production.
8+
9+
You have 3 main components:
10+
- **BusinessService**: This component aims to recieve requests from external applications.
11+
- **BusinessProcess**: This component is responsible for processing the requests and orchestrating the business logic.
12+
- **BusinessOperation**: This component is responsible for executing the technical operations that are needed to fulfill the requests.
13+
14+
The composite applications will give us access to the production through external applications like REST services.
15+
16+
The **arrows** between them all of this components are **messages**.
17+
18+
The messages are the way that the components interact with each other.
19+
20+
## How to exchange messages
21+
22+
To exchange messages between components, you can use the following methods:
23+
24+
- `send_request_sync`: This method is used to send a request synchronously. It will wait for a response before continuing.
25+
- `send_request_async`: This method is used to send a request asynchronously. It will not wait for a response before continuing.
26+
- `send_request_async_ng`: Same as `send_request_async`, but with an ayncio implementation.
27+
- `send_multi_request_sync`: This method is used to send multiple requests synchronously. It will wait for all responses before continuing.
28+
- `send_generator_request`: This method is used to send a request synchronously and return a generator.
29+
30+
## send_request_sync
31+
32+
This method is used to send a request synchronously. It will wait for a response before continuing.
33+
34+
### Function signature
35+
36+
```python
37+
def send_request_sync(self, target: str, request: Union[Message, Any],
38+
timeout: int = -1, description: Optional[str] = None) -> Any:
39+
"""Send message synchronously to target component.
40+
41+
Args:
42+
target: Name of target component
43+
request: Message to send
44+
timeout: Timeout in seconds, -1 means wait forever
45+
description: Optional description for logging
46+
47+
Returns:
48+
Response from target component
49+
50+
Raises:
51+
TypeError: If request is invalid type
52+
"""
53+
...
54+
```
55+
56+
### Example usage
57+
58+
```python
59+
from iop import BusinessProcess
60+
from msg import MyMessage
61+
62+
class MyBP(BusinessProcess):
63+
64+
def on_message(self, request):
65+
msg = MyMessage(message="Hello World")
66+
# Send a synchronous request to the target component
67+
response = self.send_request_sync("Python.MyBO", msg)
68+
self.log_info(f"Received response: {response}")
69+
```
70+
71+
## send_request_async
72+
73+
This method is used to send a request asynchronously. It will not wait for a response before continuing.
74+
75+
### Function signature (for BusinessService and BusinessOperation)
76+
77+
```python
78+
def send_request_async(self, target: str, request: Union[Message, Any],
79+
description: Optional[str] = None) -> None:
80+
"""Send message asynchronously to target component.
81+
82+
Args:
83+
target: Name of target component
84+
request: Message to send
85+
description: Optional description for logging
86+
87+
Raises:
88+
TypeError: If request is invalid type
89+
"""
90+
...
91+
```
92+
93+
### Example usage (for BusinessService and BusinessOperation)
94+
95+
```python
96+
from iop import BusinessService
97+
from msg import MyMessage
98+
99+
class MyBS(BusinessService):
100+
101+
def on_message(self, request):
102+
msg = MyMessage(message="Hello World")
103+
# Send an asynchronous request to the target component
104+
self.send_request_async("Python.MyBO", msg)
105+
self.log_info("Request sent asynchronously")
106+
```
107+
108+
### Function signature (for BusinessProcess)
109+
110+
```python
111+
def send_request_async(self, target: str, request: Any, description: Optional[str]=None, completion_key: Optional[str]=None, response_required: bool=True) -> None:
112+
"""Send the specified message to the target business process or business operation asynchronously.
113+
114+
Args:
115+
target: The name of the business process or operation to receive the request
116+
request: The message to send to the target
117+
description: An optional description property in the message header
118+
completion_key: A token to identify the completion of the request
119+
response_required: Whether a response is required
120+
121+
Raises:
122+
TypeError: If request is not of type Message or IRISObject
123+
"""
124+
...
125+
```
126+
127+
### Example usage (for BusinessProcess)
128+
129+
```python
130+
from iop import BusinessProcess
131+
from msg import MyMessage
132+
133+
class MyBP(BusinessProcess):
134+
135+
def on_message(self, request):
136+
msg_one = MyMessage(message="Message1")
137+
msg_two = MyMessage(message="Message2")
138+
139+
self.send_request_async("Python.MyBO", msg_one,completion_key="1")
140+
self.send_request_async("Python.MyBO", msg_two,completion_key="2")
141+
142+
def on_response(self, request, response, call_request, call_response, completion_key):
143+
if completion_key == "1":
144+
self.response_one = call_response
145+
elif completion_key == "2":
146+
self.response_two = call_response
147+
148+
def on_complete(self, request, response):
149+
self.log_info(f"Received response one: {self.response_one.message}")
150+
self.log_info(f"Received response two: {self.response_two.message}")
151+
```
152+
153+
## send_request_async_ng
154+
155+
This method is used to send a request asynchronously using an asyncio implementation.
156+
157+
### Function signature
158+
159+
```python
160+
async def send_request_async_ng(self, target: str, request: Union[Message, Any],
161+
timeout: int = -1, description: Optional[str] = None) -> Any:
162+
"""Send message asynchronously to target component with asyncio.
163+
164+
Args:
165+
target: Name of target component
166+
request: Message to send
167+
timeout: Timeout in seconds, -1 means wait forever
168+
description: Optional description for logging
169+
170+
Returns:
171+
Response from target component
172+
"""
173+
...
174+
```
175+
176+
### Example usage
177+
178+
```python
179+
import asyncio
180+
import random
181+
182+
from iop import BusinessProcess
183+
from msg import MyMessage
184+
185+
186+
class MyAsyncNGBP(BusinessProcess):
187+
188+
def on_message(self, request):
189+
190+
results = asyncio.run(self.await_response(request))
191+
192+
for result in results:
193+
self.logger.info(f"Received response: {result.message}")
194+
195+
return MyMessage(message="All responses received")
196+
197+
async def await_response(self, request):
198+
# create 1 to 10 messages
199+
tasks = []
200+
for i in range(random.randint(1, 10)):
201+
tasks.append(self.send_request_async_ng("Python.MyAsyncNGBO",
202+
MyMessage(message=f"Message {i}")))
203+
204+
return await asyncio.gather(*tasks)
205+
206+
```
207+
208+
## send_multi_request_sync
209+
210+
This method is used to send multiple requests synchronously. It will wait for all responses before continuing.
211+
212+
### Function signature
213+
214+
```python
215+
def send_multi_request_sync(self, target_request: List[Tuple[str, Union[Message, Any]]],
216+
timeout: int = -1, description: Optional[str] = None) -> List[Tuple[str, Union[Message, Any], Any, int]]:
217+
"""Send multiple messages synchronously to target components.
218+
219+
Args:
220+
target_request: List of tuples (target, request) to send
221+
timeout: Timeout in seconds, -1 means wait forever
222+
description: Optional description for logging
223+
224+
Returns:
225+
List of tuples (target, request, response, status)
226+
227+
Raises:
228+
TypeError: If target_request is not a list of tuples
229+
ValueError: If target_request is empty
230+
"""
231+
...
232+
```
233+
234+
### Example usage
235+
236+
```python
237+
from iop import BusinessProcess
238+
from msg import MyMessage
239+
240+
241+
class MyMultiBP(BusinessProcess):
242+
243+
def on_message(self, request):
244+
msg_one = MyMessage(message="Message1")
245+
msg_two = MyMessage(message="Message2")
246+
247+
tuple_responses = self.send_multi_request_sync([("Python.MyMultiBO", msg_one),
248+
("Python.MyMultiBO", msg_two)])
249+
250+
self.log_info("All requests have been processed")
251+
for target,request,response,status in tuple_responses:
252+
self.log_info(f"Received response: {response.message}")
253+
```
254+
255+
## send_generator_request
256+
257+
This method is used to send a request synchronously and return a generator.
258+
259+
### Function signature
260+
261+
```python
262+
def send_generator_request(self, target: str, request: Union[Message, Any],
263+
timeout: int = -1, description: Optional[str] = None) -> _GeneratorRequest:
264+
"""Send message as a generator request to target component.
265+
Args:
266+
target: Name of target component
267+
request: Message to send
268+
timeout: Timeout in seconds, -1 means wait forever
269+
description: Optional description for logging
270+
Returns:
271+
_GeneratorRequest: An instance of _GeneratorRequest to iterate over responses
272+
Raises:
273+
TypeError: If request is not of type Message
274+
"""
275+
...
276+
```
277+
278+
### Example usage
279+
280+
```python
281+
from typing import Any
282+
from iop import BusinessProcess,BusinessOperation
283+
284+
from msg import MyGenerator,MyGeneratorResponse
285+
286+
class MyGeneratorProcess(BusinessProcess):
287+
288+
def on_request(self, request: Any) -> Any:
289+
gen = self.send_generator_request(
290+
target="User.MyGeneratorOperation",
291+
request=MyGenerator(my_string="Hello, World!"),
292+
timeout=10,
293+
description="My generator request")
294+
295+
for response in gen:
296+
self.log_info(f"Received response: {response}")
297+
298+
class MyGeneratorOperation(BusinessOperation):
299+
300+
def on_private_session_started(self, request: MyGenerator) -> Any:
301+
# return the generator to the process that called it
302+
return self.my_generator(request)
303+
304+
def my_generator(self, request: Any) -> Any:
305+
self.log_info(f"Processing request: {request}")
306+
# Simulate some processing and yield responses
307+
for i in range(5):
308+
response = f"Response {i} from MyGeneratorOperation"
309+
self.log_info(response)
310+
yield MyGeneratorResponse(my_other_string=response) # notice that we yield a response here
311+
```
312+

docs/img/FrameworkFull.png

61.6 KB
Loading

0 commit comments

Comments
 (0)