Skip to content

Releases: lwinterface/panini

Release v0.8.4

29 Apr 16:09
936fa3f
Compare
Choose a tag to compare

Panini v0.8.4 Updates:

  • Added ability to exclude specific subjects via config.
  • Implemented fixes to Tracing Middleware for enhanced stability.

Release v0.8.2

28 Jun 17:00
Compare
Choose a tag to compare

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:

@vlad-zverev

Introducing Panini v0.8.1: Enhanced Tracing Middleware for Improved Debugging and Performance Analysis

19 Apr 15:52
Compare
Choose a tag to compare

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

20 Dec 19:10
Compare
Choose a tag to compare

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

01 Apr 16:15
b60b5b2
Compare
Choose a tag to compare
  • 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

14 Feb 09:06
e620e8b
Compare
Choose a tag to compare
  • 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

11 Nov 14:11
3f69567
Compare
Choose a tag to compare
  • Fixed bug: tasks don't works with HTTP server
  • Fixed package incompatibility

Release v0.6.0

05 Nov 14:19
65d45d9
Compare
Choose a tag to compare
  • Global refactoring
  • Added new interface for pereodic tasks: @app.task(interval=1)
  • Changed listen_subject_only_if_include param in App to function app.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

17 Aug 09:56
1f330e5
Compare
Choose a tag to compare

Added ability to use any parameters for aiohttp including ssl_context(for HTTPS)

Release v0.5.0

21 Jul 08:31
3ae4f4f
Compare
Choose a tag to compare
  • Implemented AsyncTestClient for better testing experience
  • Added listen_subject_only_if_exclude parameter for excluding unnecessary subjects