jararaca 0.2.37a11__py3-none-any.whl → 0.2.37a12__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.
jararaca/cli.py CHANGED
@@ -1,5 +1,8 @@
1
1
  import importlib
2
2
  import importlib.resources
3
+ import os
4
+ import sys
5
+ import time
3
6
  from codecs import StreamWriter
4
7
  from typing import Any
5
8
  from urllib.parse import urlparse, urlunsplit
@@ -208,12 +211,83 @@ def scheduler(
208
211
  "file_path",
209
212
  type=click.File("w"),
210
213
  )
211
- def gen_tsi(app_path: str, file_path: StreamWriter) -> None:
212
- app = find_microservice_by_module_path(app_path)
214
+ @click.option(
215
+ "--watch",
216
+ is_flag=True,
217
+ help="Watch for file changes and regenerate TypeScript interfaces",
218
+ )
219
+ @click.option(
220
+ "--src-dir",
221
+ type=click.Path(exists=True, file_okay=False, dir_okay=True),
222
+ default="src",
223
+ help="Source directory to watch for changes (default: src)",
224
+ )
225
+ def gen_tsi(app_path: str, file_path: StreamWriter, watch: bool, src_dir: str) -> None:
226
+ """Generate TypeScript interfaces from a Python microservice."""
227
+
228
+ # Generate typescript interfaces
229
+ def generate_interfaces() -> None:
230
+ try:
231
+ app = find_microservice_by_module_path(app_path)
232
+ content = write_microservice_to_typescript_interface(app)
233
+
234
+ # Save current position
235
+ file_path.tell()
236
+
237
+ # Reset file to beginning
238
+ file_path.seek(0)
239
+ file_path.truncate()
240
+
241
+ # Write new content
242
+ file_path.write(content)
243
+ file_path.flush()
213
244
 
214
- content = write_microservice_to_typescript_interface(app)
245
+ print(f"Generated TypeScript interfaces at {time.strftime('%H:%M:%S')}")
246
+ except Exception as e:
247
+ print(f"Error generating TypeScript interfaces: {e}", file=sys.stderr)
215
248
 
216
- file_path.write(content)
249
+ # Initial generation
250
+ generate_interfaces()
251
+
252
+ # If watch mode is not enabled, exit
253
+ if not watch:
254
+ return
255
+
256
+ try:
257
+ from watchdog.events import FileSystemEvent, FileSystemEventHandler
258
+ from watchdog.observers import Observer
259
+ except ImportError:
260
+ print(
261
+ "Watchdog is required for watch mode. Install it with: pip install watchdog",
262
+ file=sys.stderr,
263
+ )
264
+ return
265
+
266
+ # Set up file system event handler
267
+ class PyFileChangeHandler(FileSystemEventHandler):
268
+ def on_modified(self, event: FileSystemEvent) -> None:
269
+ src_path = (
270
+ event.src_path
271
+ if isinstance(event.src_path, str)
272
+ else str(event.src_path)
273
+ )
274
+ if not event.is_directory and src_path.endswith(".py"):
275
+ print(f"File changed: {src_path}")
276
+ generate_interfaces()
277
+
278
+ # Set up observer
279
+ observer = Observer()
280
+ observer.schedule(PyFileChangeHandler(), src_dir, recursive=True)
281
+ observer.start()
282
+
283
+ print(f"Watching for changes in {os.path.abspath(src_dir)}...")
284
+ try:
285
+ while True:
286
+ time.sleep(1)
287
+ except KeyboardInterrupt:
288
+ observer.stop()
289
+ print("Watch mode stopped")
290
+ observer.join()
217
291
 
218
292
 
219
293
  def camel_case_to_snake_case(name: str) -> str:
@@ -205,17 +205,17 @@ class MessageHandlerCallback:
205
205
  self, aio_pika_message: aio_pika.abc.AbstractIncomingMessage
206
206
  ) -> None:
207
207
 
208
- rounting_key = self.queue_name
208
+ routing_key = self.queue_name
209
209
 
210
- if rounting_key is None:
210
+ if routing_key is None:
211
211
  logger.warning("No topic found for message")
212
212
  await self.handle_reject_message(aio_pika_message)
213
213
  return
214
214
 
215
- handler_data = self.consumer.incoming_map.get(rounting_key)
215
+ handler_data = self.consumer.incoming_map.get(routing_key)
216
216
 
217
217
  if handler_data is None:
218
- logger.warning("No handler found for topic '%s'" % rounting_key)
218
+ logger.warning("No handler found for topic '%s'" % routing_key)
219
219
  await self.handle_reject_message(aio_pika_message)
220
220
 
221
221
  return
@@ -227,7 +227,7 @@ class MessageHandlerCallback:
227
227
  if len(sig.parameters) != 1:
228
228
  logger.warning(
229
229
  "Handler for topic '%s' must have exactly one parameter which is MessageOf[T extends Message]"
230
- % rounting_key
230
+ % routing_key
231
231
  )
232
232
  return
233
233
 
@@ -238,14 +238,14 @@ class MessageHandlerCallback:
238
238
  if param_origin is not MessageOf:
239
239
  logger.warning(
240
240
  "Handler for topic '%s' must have exactly one parameter of type Message"
241
- % rounting_key
241
+ % routing_key
242
242
  )
243
243
  return
244
244
 
245
245
  if len(parameter.annotation.__args__) != 1:
246
246
  logger.warning(
247
247
  "Handler for topic '%s' must have exactly one parameter of type Message"
248
- % rounting_key
248
+ % routing_key
249
249
  )
250
250
  return
251
251
 
@@ -253,8 +253,8 @@ class MessageHandlerCallback:
253
253
 
254
254
  if not issubclass(message_type, BaseModel):
255
255
  logger.warning(
256
- "Handler for topic '%s' must have exactly one parameter of type Message[BaseModel]"
257
- % rounting_key
256
+ "Handler for topic '%s' must have exactly one parameter of type MessageOf[BaseModel]"
257
+ % routing_key
258
258
  )
259
259
  return
260
260
 
@@ -266,7 +266,7 @@ class MessageHandlerCallback:
266
266
  async with self.consumer.uow_context_provider(
267
267
  MessageBusAppContext(
268
268
  message=builded_message,
269
- topic=rounting_key,
269
+ topic=routing_key,
270
270
  )
271
271
  ):
272
272
  ctx: AsyncContextManager[Any]
@@ -293,7 +293,7 @@ class MessageHandlerCallback:
293
293
  )
294
294
  else:
295
295
  logger.exception(
296
- f"Error processing message on topic {rounting_key}"
296
+ f"Error processing message on topic {routing_key}"
297
297
  )
298
298
  if incoming_message_spec.requeue_on_exception:
299
299
  await self.handle_reject_message(aio_pika_message, requeue=True)
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.3
2
+ Name: jararaca
3
+ Version: 0.2.37a12
4
+ Summary: A simple and fast API framework for Python
5
+ Author: Lucas S
6
+ Author-email: me@luscasleo.dev
7
+ Requires-Python: >=3.11,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Provides-Extra: docs
13
+ Provides-Extra: http
14
+ Provides-Extra: opentelemetry
15
+ Requires-Dist: aio-pika (>=9.4.3,<10.0.0)
16
+ Requires-Dist: croniter (>=3.0.3,<4.0.0)
17
+ Requires-Dist: fastapi (>=0.113.0,<0.114.0)
18
+ Requires-Dist: mako (>=1.3.5,<2.0.0)
19
+ Requires-Dist: opentelemetry-api (>=1.27.0,<2.0.0) ; extra == "opentelemetry"
20
+ Requires-Dist: opentelemetry-distro (>=0.49b2,<0.50) ; extra == "opentelemetry"
21
+ Requires-Dist: opentelemetry-exporter-otlp (>=1.27.0,<2.0.0) ; extra == "opentelemetry"
22
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.27.0,<2.0.0) ; extra == "opentelemetry"
23
+ Requires-Dist: opentelemetry-sdk (>=1.27.0,<2.0.0) ; extra == "opentelemetry"
24
+ Requires-Dist: redis (>=5.0.8,<6.0.0)
25
+ Requires-Dist: sqlalchemy (>=2.0.34,<3.0.0)
26
+ Requires-Dist: types-croniter (>=3.0.3.20240731,<4.0.0.0)
27
+ Requires-Dist: types-redis (>=4.6.0.20240903,<5.0.0.0)
28
+ Requires-Dist: uvicorn (>=0.30.6,<0.31.0)
29
+ Requires-Dist: uvloop (>=0.20.0,<0.21.0)
30
+ Requires-Dist: websockets (>=13.0.1,<14.0.0)
31
+ Project-URL: Repository, https://github.com/LuscasLeo/jararaca
32
+ Description-Content-Type: text/markdown
33
+
34
+ <img src="https://raw.githubusercontent.com/LuscasLeo/jararaca/main/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg" alt="Jararaca Logo" width="250" float="right">
35
+
36
+ # Jararaca Microservice Framework
37
+
38
+ ## Overview
39
+
40
+ Jararaca is an async-first microservice framework designed to simplify the development of distributed systems. It provides a comprehensive set of tools for building robust, scalable, and maintainable microservices with a focus on developer experience and type safety.
41
+
42
+ ## Key Features
43
+
44
+ ### REST API Development
45
+ - Easy-to-use interfaces for building REST APIs
46
+ - Automatic request/response validation
47
+ - Type-safe endpoints with FastAPI integration
48
+ - Automatic OpenAPI documentation generation
49
+
50
+ ### Message Bus Integration
51
+ - Topic-based message bus for event-driven architecture
52
+ - Support for both worker and publisher patterns
53
+ - Built-in message serialization and deserialization
54
+ - Easy integration with AIO Pika for RabbitMQ
55
+
56
+ ### Distributed WebSocket
57
+ - Room-based WebSocket communication
58
+ - Distributed broadcasting across multiple backend instances
59
+ - Automatic message synchronization between instances
60
+ - Built-in connection management and room handling
61
+
62
+ ### Task Scheduling
63
+ - Cron-based task scheduling
64
+ - Support for overlapping and non-overlapping tasks
65
+ - Distributed task execution
66
+ - Easy integration with message bus for task distribution
67
+
68
+ ### TypeScript Integration
69
+ - Automatic TypeScript interface generation
70
+ - Command-line tool for generating TypeScript types
71
+ - Support for REST endpoints, WebSocket events, and message bus payloads
72
+ - Type-safe frontend-backend communication
73
+
74
+ ### Hexagonal Architecture
75
+ - Clear separation of concerns
76
+ - Business logic isolation from infrastructure
77
+ - Easy testing and maintainability
78
+ - Dependency injection for flexible component management
79
+
80
+ ### Observability
81
+ - Built-in OpenTelemetry integration
82
+ - Distributed tracing support
83
+ - Logging and metrics collection
84
+ - Performance monitoring capabilities
85
+
86
+ ## Quick Start
87
+
88
+ ### Installation
89
+
90
+ ```bash
91
+ pip install jararaca
92
+ ```
93
+
94
+ ### Basic Usage
95
+
96
+ ```python
97
+ from jararaca import Microservice, create_http_server
98
+ from jararaca.presentation.http_microservice import HttpMicroservice
99
+
100
+ # Define your microservice
101
+ app = Microservice(
102
+ providers=[
103
+ # Add your providers here
104
+ ],
105
+ controllers=[
106
+ # Add your controllers here
107
+ ],
108
+ interceptors=[
109
+ # Add your interceptors here
110
+ ],
111
+ )
112
+
113
+ # Create HTTP server
114
+ http_app = HttpMicroservice(app)
115
+ web_app = create_http_server(app)
116
+ ```
117
+
118
+ ### Running the Service
119
+
120
+ ```bash
121
+ # Run as HTTP server
122
+ jararaca server app:http_app
123
+
124
+ # Run as message bus worker
125
+ jararaca worker app:app
126
+
127
+ # Run as scheduler
128
+ jararaca scheduler app:app
129
+
130
+ # Generate TypeScript interfaces
131
+ jararaca gen-tsi app.main:app app.ts
132
+ ```
133
+
134
+ ## Documentation
135
+
136
+ For detailed documentation, please visit our [documentation site](https://luscasleo.github.io/jararaca/).
137
+
138
+ ## Examples
139
+
140
+ Check out the [examples directory](examples/) for complete working examples of:
141
+ - REST API implementation
142
+ - WebSocket usage
143
+ - Message bus integration
144
+ - Task scheduling
145
+ - TypeScript interface generation
146
+
147
+ ## Contributing
148
+
149
+ Contributions are welcome! Please read our [contributing guidelines](.github/CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
150
+
151
+ ## License
152
+
153
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
154
+
@@ -1,9 +1,6 @@
1
- LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
2
- README.md,sha256=mte30I-ZEJJp-Oax-OganNgl6G9GaCZPL6JVFAvZGz4,7034
3
- pyproject.toml,sha256=6qmtrXrdw7bJZOL_-RGgWJtkCmz7b42Xbc-NwubeGTQ,1840
4
1
  jararaca/__init__.py,sha256=VBrN25GHJ3gDG95CcJWe3dmGcA-X2agzOCIBbjzc1Iw,15312
5
2
  jararaca/__main__.py,sha256=-O3vsB5lHdqNFjUtoELDF81IYFtR-DSiiFMzRaiSsv4,67
6
- jararaca/cli.py,sha256=JKk4xrRbtX2fM8yYw794lbxvJFH73bWw3GGIvrpAkeE,5706
3
+ jararaca/cli.py,sha256=K6df8fqEc4Qj-yGz5hmO3pSgFWxcLP4iciOP4LHida4,7979
7
4
  jararaca/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
5
  jararaca/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
6
  jararaca/core/providers.py,sha256=wktH84FK7c1s2wNq-fudf1uMfi3CQBR0neU2czJ_L0U,434
@@ -18,7 +15,7 @@ jararaca/messagebus/interceptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
18
15
  jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py,sha256=BPH5wOlj_CyHtJ7W4NWF2h0gYMwzOPNzFhGADk618N4,4373
19
16
  jararaca/messagebus/publisher.py,sha256=5ay9Znwybqt981OOykdWkFisSvGiTeTpPXDFLMnaiqg,1109
20
17
  jararaca/messagebus/types.py,sha256=iYLyLxWqOHkDadxyMqQPWy3itLNQfvD6oQe8jcq9nzo,887
21
- jararaca/messagebus/worker.py,sha256=hKACTyrIMHcuaySpmI3UhDCja6va1gGkFRoZJ7kYfoA,13613
18
+ jararaca/messagebus/worker.py,sha256=_X2Ctj7bI9XjCMvQMy8jM3dEE3CGnqgrU_B3lTGfmmQ,13605
22
19
  jararaca/microservice.py,sha256=1TvDKVMMREH27Ly8eTEheMmSfro4_Az_JKM_NdDvrgc,6636
23
20
  jararaca/observability/decorators.py,sha256=XffBinFXdiNkY6eo8_1nkr_GapM0RUGBg0aicBIelag,2220
24
21
  jararaca/observability/interceptor.py,sha256=GHkuGKFWftN7MDjvYeGFGEPnuJETNhtxRK6yuPrCrpU,1462
@@ -59,8 +56,8 @@ jararaca/tools/app_config/decorators.py,sha256=-ckkMZ1dswOmECdo1rFrZ15UAku--txaN
59
56
  jararaca/tools/app_config/interceptor.py,sha256=nfFZiS80hrbnL7-XEYrwmp2rwaVYBqxvqu3Y-6o_ov4,2575
60
57
  jararaca/tools/metadata.py,sha256=7nlCDYgItNybentPSSCc2MLqN7IpBd0VyQzfjfQycVI,1402
61
58
  jararaca/tools/typescript/interface_parser.py,sha256=4SHt094P-QawMFHSyMCiujQf8Niw7xACIO1RHBM8-w4,29192
62
- jararaca-0.2.37a11.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
63
- jararaca-0.2.37a11.dist-info/METADATA,sha256=o0sSsRaTx6-ySotULbIhDQtza302CTjxCc9jdAJxbJ8,8555
64
- jararaca-0.2.37a11.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
65
- jararaca-0.2.37a11.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
66
- jararaca-0.2.37a11.dist-info/RECORD,,
59
+ jararaca-0.2.37a12.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
60
+ jararaca-0.2.37a12.dist-info/METADATA,sha256=W8aHUpqo5Q5iGBwX0BE4CS9MfEEMN97vM-YRuCJ2URM,4873
61
+ jararaca-0.2.37a12.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
62
+ jararaca-0.2.37a12.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
63
+ jararaca-0.2.37a12.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.1
2
+ Generator: poetry-core 2.1.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
README.md DELETED
@@ -1,243 +0,0 @@
1
- <img src="https://raw.githubusercontent.com/LuscasLeo/jararaca/main/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg" alt="README.md" width="250" float="right">
2
-
3
- # Jararaca Microservice Framework
4
-
5
- ## Overview
6
-
7
- Jararaca is a aio-first microservice framework that provides a set of tools to build and deploy microservices in a simple and clear way.
8
-
9
- ## Features
10
-
11
- ### Hexagonal Architecture
12
-
13
- The framework is based on the hexagonal architecture, which allows you to separate the business logic from the infrastructure, making the code more testable and maintainable.
14
-
15
- ### Dependency Injection
16
-
17
- The framework uses the dependency injection pattern to manage the dependencies between the components of the application.
18
-
19
- ```py
20
- app = Microservice(
21
- providers=[
22
- ProviderSpec(
23
- provide=Token(AuthConfig, "AUTH_CONFIG"),
24
- use_value=AuthConfig(
25
- secret="secret",
26
- identity_refresh_token_expires_delta_seconds=60 * 60 * 24 * 30,
27
- identity_token_expires_delta_seconds=60 * 60,
28
- ),
29
- ),
30
- ProviderSpec(
31
- provide=Token(AppConfig, "APP_CONFIG"),
32
- use_factory=AppConfig.provider,
33
- ),
34
- ProviderSpec(
35
- provide=TokenBlackListService,
36
- use_value=InMemoryTokenBlackListService(),
37
- ),
38
- ],
39
- )
40
- ```
41
-
42
- ### Web Server Port
43
-
44
- The framework provides a web server that listens on a specific port and routes the requests to the appropriate handler. It uses [FastAPI](https://fastapi.tiangolo.com/) as the web framework.
45
-
46
- ```py
47
- @Delete("/{task_id}")
48
- async def delete_task(self, task_id: TaskId) -> None:
49
- await self.tasks_crud.delete_by_id(task_id)
50
-
51
- await use_ws_manager().broadcast(("Task %s deleted" % task_id).encode())
52
- ```
53
-
54
- ### Message Bus
55
-
56
- The framework provides a topic-based message bus that allows you to send messages between the components of the application. It uses [AIO Pika](https://aio-pika.readthedocs.io/) as the message broker worker and publisher.
57
-
58
- ```py
59
- @IncomingHandler("task")
60
- async def process_task(self, message: Message[Identifiable[TaskSchema]]) -> None:
61
- name = generate_random_name()
62
- now = asyncio.get_event_loop().time()
63
- print("Processing task: ", name)
64
-
65
- task = message.payload()
66
-
67
- print("Received task: ", task)
68
- await asyncio.sleep(random.randint(1, 5))
69
-
70
- await use_publisher().publish(task, topic="task")
71
-
72
- then = asyncio.get_event_loop().time()
73
- print("Task Finished: ", name, " Time: ", then - now)
74
- ```
75
-
76
- ### Distributed Websocket
77
-
78
- You can setup a room-based websocket server that allows you to send messages to a specific room or broadcast messages to all connected clients. All backend instances communicates with each other using a pub/sub mechanism (such as Redis).
79
-
80
- ```py
81
- @WebSocketEndpoint("/ws")
82
- async def ws_endpoint(self, websocket: WebSocket) -> None:
83
- await websocket.accept()
84
- counter.increment()
85
- await use_ws_manager().add_websocket(websocket)
86
- await use_ws_manager().join(["tasks"], websocket)
87
- await use_ws_manager().broadcast(
88
- ("New Connection (%d) from %s" % (counter.count, self.hostname)).encode()
89
- )
90
-
91
- print("New Connection (%d)" % counter.count)
92
-
93
- while True:
94
- try:
95
- await websocket.receive_text()
96
- except WebSocketDisconnect:
97
- counter.decrement()
98
- await use_ws_manager().remove_websocket(websocket)
99
-
100
- await use_ws_manager().broadcast(
101
- (
102
- "Connection Closed (%d) from %s"
103
- % (counter.count, self.hostname)
104
- ).encode()
105
- )
106
- print("Connection Closed (%d)" % counter.count)
107
- break
108
- ```
109
-
110
- ### Scheduled Routine
111
-
112
- You can setup a scheduled routine that runs a specific task at a specific time or interval.
113
-
114
- ```py
115
- ...
116
- @ScheduledAction("* * * * * */3", allow_overlap=False)
117
- async def scheduled_task(self) -> None:
118
- print("Scheduled Task at ", asyncio.get_event_loop().time())
119
-
120
- print("sleeping")
121
- await asyncio.sleep(5)
122
-
123
- await use_publisher().publish(
124
- message=Identifiable(
125
- id=uuid4(),
126
- data=TaskSchema(name=generate_random_name()),
127
- ),
128
- topic="task",
129
- )
130
- ```
131
-
132
- ### Observability
133
-
134
- You can setup Observability Interceptors for logs, traces and metric collection with [OpenTelemetry](https://opentelemetry.io/docs)-based Protocols
135
-
136
- ```python
137
- class HelloService:
138
- def __init__(
139
- self,
140
- hello_rpc: Annotated[HelloRPC, Token(HelloRPC, "HELLO_RPC")],
141
- ):
142
- self.hello_rpc = hello_rpc
143
-
144
- @TracedFunc("ping") # Decorator for tracing
145
- async def ping(self) -> HelloResponse:
146
- return await self.hello_rpc.ping()
147
-
148
- @TracedFunc("hello-service")
149
- async def hello(
150
- self,
151
- gather: bool,
152
- ) -> HelloResponse:
153
- now = asyncio.get_event_loop().time()
154
- if gather:
155
- await asyncio.gather(*[self.random_await(a) for a in range(10)])
156
- else:
157
- for a in range(10):
158
- await self.random_await(a)
159
- return HelloResponse(
160
- message="Elapsed time: {}".format(asyncio.get_event_loop().time() - now)
161
- )
162
-
163
- @TracedFunc("random-await")
164
- async def random_await(self, index: int) -> None:
165
- logger.info("Random await %s", index, extra={"index": index})
166
- await asyncio.sleep(random.randint(1, 3))
167
- logger.info("Random await %s done", index, extra={"index": index})
168
- ```
169
-
170
- ## Installation
171
-
172
- ```bash
173
- pip install jararaca
174
- ```
175
-
176
- ## Usage
177
-
178
- ### Create a Microservice
179
-
180
- ```python
181
- # app.py
182
-
183
- from jararaca import Microservice, create_http_server, create_messagebus_worker
184
- from jararaca.presentation.http_microservice import HttpMicroservice
185
-
186
- app = Microservice(
187
- providers=[
188
- ProviderSpec(
189
- provide=Token[AppConfig],
190
- use_factory=AppConfig.provider,
191
- )
192
- ],
193
- controllers=[TasksController],
194
- interceptors=[
195
- AIOSqlAlchemySessionInterceptor(
196
- AIOSQAConfig(
197
- connection_name="default",
198
- url="sqlite+aiosqlite:///db.sqlite3",
199
- )
200
- ),
201
- ],
202
- )
203
-
204
-
205
- # App for specific Http Configuration Context
206
- http_app = HttpMicroservice(app)
207
-
208
- web_app = create_http_server(app)
209
-
210
- ```
211
-
212
- ### Run as a Web Server
213
-
214
- ```bash
215
- uvicorn app:web_app --reload
216
- # or
217
- jararaca server app:app
218
- # or
219
- jararaca server app:http_app
220
-
221
- ```
222
-
223
- ### Run as a Message Bus Worker
224
-
225
- ```bash
226
- jararaca worker app:app
227
- ```
228
-
229
- ### Run as a scheduled routine
230
-
231
- ```bash
232
- jararaca scheduler app:app
233
- ```
234
-
235
- ### Generate Typescript intefaces from microservice app controllers
236
-
237
- ```bash
238
- jararaca gen-tsi app.main:app app.ts
239
- ```
240
-
241
- ### Documentation
242
-
243
- Documentation is under construction [here](https://luscasleo.github.io/jararaca/).