Releases: lwinterface/panini
Release v0.8.4
Release v0.8.2
Summary:
This release introduces a new feature to enhance fail tolerance by ignoring exceptions in the main loop. It addresses an issue where any internal exception in NATS could lead to a crash of the entire application.
Changes Made:
Added an optional flag to enable/disable ignoring exceptions in the main loop.
Implemented the flag as a parameter "ignore_exceptions" in the panini.App class.
By default, the flag is enabled to ensure better fail tolerance.
Contributor:
Introducing Panini v0.8.1: Enhanced Tracing Middleware for Improved Debugging and Performance Analysis
We're excited to announce the release of Panini v0.8.1, which brings a powerful new feature to our Python microframework: an enhanced Tracing Middleware. With this update, developers can easily trace their NATS microservices, allowing for more effective debugging and performance analysis.
The new Tracing Middleware leverages OpenTelemetry and integrates with Jaeger and Grafana, providing a comprehensive solution for monitoring your microservices. With custom span configurations, you can gain granular insights into your service operations and quickly identify bottlenecks or potential issues.
Key features in this release:
- Middleware for tracing @app.listen and app.publish/request actions
- Customizable trace attributes with SpanConfig
- Optional tracing for specific endpoints or publish/request tasks
- Easy integration with Jaeger and Grafana for trace visualization and analysis
- To get started with the new Tracing Middleware, check out the detailed documentation and example code at https://github.com/lwinterface/panini/tree/main/examples/tracing_middleware_compose .
A huge thank you to Igor Hwang @i2gor87 for contributing this fantastic feature to the Panini community!
Upgrade to Panini v0.8.1 today and enjoy the benefits of tracing and performance analysis for your NATS microservices!
v0.8.0
New Updates to Panini v0.8.0
Parameter data_type "json" removed
In v0.8.0, we have removed the data type "json" from the parameter list, as it was referring to a jsonble Python object which was not the most explicit data type name. This may have caused confusion among developers, so we decided to remove it.
No Need to Declare "data_type" for "publish" and "request"
Panini detects a type of your message by itself.
New Parameter for “request” method - “response_data_type”
For example:
subject = "a.b.c"
message = {"param1": "value1"}
response: bytes = app.request(subject=subject, message=message, response_data_type=bytes)
Panini Supports Dataclass as data_type
You may use it to serialize or validate your messages. I’ve tested it mostly with Pydantic dataclasses and also with Mashumaro. Example of usage is here:
import asyncio
from panini import app as panini_app
from pydantic import BaseModel
papp = panini_app.App(
service_name="validators",
host="127.0.0.1",
port=4222,
)
log = papp.logger
class SubTestData(BaseModel):
subkey1: str
subkey2: int
class TestMessage(BaseModel):
key1: str
key2: int
key3: float
key4: list
key5: dict
key6: SubTestData
key7: int = None
key8: int = None
message = {
"key1": "value1",
"key2": 2,
"key3": 3.0,
"key4": [1, 2, 3, 4],
"key5": {"1": 1, "2": 2, "3": 3, "4": 4, "5": 5},
"key6": {"subkey1": "1", "subkey2": 2, "3": 3, "4": 4, "5": 5},
"key7": None,
}
@papp.task()
async def publish_dataclass():
for _ in range(10):
message_dataclass = TestMessage(**message)
await papp.publish(
subject="some.publish.subject",
message=message_dataclass
)
@papp.listen("some.publish.subject", data_type=TestMessage)
async def receive_dataclass(msg):
log.info(f"got message {msg.data}")
await asyncio.sleep(1)
if __name__ == "__main__":
papp.start()
Experimental: Custom data_type with Callable Object
Panini supports any Callable object as data_type for custom processing. An example of usage is here:
from panini.exceptions import MessageSchemaError
from panini import app as panini_app
app = panini_app.App(
service_name="test_serializer_callable",
host="127.0.0.1",
port=4222,
)
def callable_validator(message):
if type(message) is not dict:
raise MessageSchemaError("type(data) is not dict")
if "data" not in message:
raise MessageSchemaError("'data' not in message")
if type(message["data"]) is not int:
raise MessageSchemaError("type(message['data']) is not int")
if message["data"] < 0:
raise MessageSchemaError(f"Value of field 'data' is {message['data']} that negative")
message["data"] += 1
return message
@app.listen("test_validator.foo", data_type=callable_validator)
async def publish(msg):
return {"success": True}
@app.listen("test_validator.foo-with-error-cb", data_type=callable_validator)
async def publish(msg):
return {"success": True}
@app.listen("test_validator.check")
async def check(msg):
try:
message = callable_validator(**msg.data)
except MessageSchemaError:
return {"success": False}
return {"success": True}
if __name__ == "__main__":
app.start()
Panini Validator Removed
If you need incoming message validation, we recommend to use dataclasses. Example of usage for Pydantic: https://pydantic-docs.helpmanual.io/usage/validators/
JetStream Syntax Support
Panini now supports JetStream syntax for streams. Examples
Removed validation_error_cb
The validation_error_cb
parameter has been removed from the listen decorator.
Release v0.7.1
- added custom logger to panini app instead of internal one
- added headers to request
- added
validation_error_cb
to listen decorator, usage:
async def custom_validation_error_cb(msg):
# custom msg handling
log.error(f"something wrong")
@app.listen("some.subject", validator=SomeValidator, validation_error_cb=custom_validation_error_cb)
async def foo(msg):
# msg handling if everything allright
log.info(f"got message {msg.data}")
- experimental: do not wait for the received message to be processed, immediately take the next mesage
Release v0.7.0
- Support NATS 2.0🎉. Now the panini stands on shoulders of nats-py v2.0.0
- Support Python 3.10
- Introducing on_start_task
Example:
from panini import app as panini_app
app = panini_app.App(
service_name="js_publish",
host="127.0.0.1",
port=4222,
enable_js=True
)
log = app.logger
NUM = 0
@app.on_start_task()
async def on_start_task():
await app.nats.js_client.add_stream(name="sample-stream-1", subjects=["test.*.stream"])
def get_message():
return {
"id": app.nats.client.client_id,
}
@app.timer_task(interval=2)
async def publish_periodically():
subject = "test.app2.stream"
message = get_message()
global NUM
NUM+=1
message['counter'] = NUM
await app.publish(subject=subject, message=message)
log.info(f"sent {message}")
if __name__ == "__main__":
app.start()
- Introducing minimal JetStream support
Since Panini switched from asyncio-nats-client to nats-py, it has become possible to support one of the most important features of NATS 2.0 - JetStream. Panini v0.7.0 does not implement an interface to JetStream at the framework level. Instead, it is suggested to use directly nats-py. Example JetStream publisher microservice:
from panini import app as panini_app
app = panini_app.App(
service_name="js_listen_push",
host="127.0.0.1",
port=4222,
enable_js=True
)
log = app.logger
NUM = 0
@app.task()
async def subscribe_to_js_stream_push():
async def cb(msg):
log.info(f"got JS message ! {msg.subject}:{msg.data}")
await app.nats.js_client.subscribe("test.*.stream", cb=cb, durable='consumer-1', stream="sample-stream-1")
if __name__ == "__main__":
app.start()
See more details in the documentation: https://panini.technology/JetStream.html
A full-fledged extension of the Panini interface for JetStream is expected in the next versions of Panini.
Release v0.6.2
- Fixed bug: tasks don't works with HTTP server
- Fixed package incompatibility
Release v0.6.0
- Global refactoring
- Added new interface for pereodic tasks: @app.task(interval=1)
- Changed
listen_subject_only_if_include
param in App to functionapp.add_filters(include, exclude)
- Added ability to use all authorization methods from nats.py
- Added ability to establish connection to multiple NATS brokers
- Added start message when starting in terminal
Release v0.5.2
Added ability to use any parameters for aiohttp including ssl_context(for HTTPS)
Release v0.5.0
- Implemented AsyncTestClient for better testing experience
- Added listen_subject_only_if_exclude parameter for excluding unnecessary subjects