Skip to main content

Simple message/event passing with asyncio and threading support.

Project description

Asyncraft: Simple event/message passing library with asyncio and threading support

A simple event/message passing library for Python 3.8+ supporting asyncio and threading.
For examples, see the examples directory.

Installation

pip install asyncraft

Messages

Messages are the first major part of the Asyncraft library. They are used to send data between different parts of the program. Keys are used for identifying handlers, which should process the given message. Further, Asyncraft supports messages with multiple keys.

import asyncraft
...
# Create a message
message = asyncraft.Message(key='key', value='value')
# Broadcast the message (threadsafe)
asyncraft.broadcast(message)
...

Handlers

The second major part of the Asyncraft library are handlers. Handlers are used for processing messages. They can be synchronous or asynchronous. Synchronous handlers are executed in a separate thread, while asynchronous handlers are executed in an asyncio event loop.

import asyncraft
from asyncraft.handler import SyncHandler, AsyncHandler
...
# Create a sync handler with decorator.
# All sync handlers will be executed in a separate thread of a thread pool.
@asyncraft.asyncraft_handler(keys=["key"])
def handler_0(message):
    print(message)
    #Handlers can return a message
    return asyncraft.Message(key='key1', value='value1')
...

# Create an async handler with decorator
# All async handlers will be executed in an asyncio event loop.
@asyncraft.asyncraft_handler(keys=["key"])
async def handler_1(message):
    print(message)
...

# Create a sync handler without decorator
# First define the callback function
def handler_2_function(message):
    print(message)
#Then create the handler
handler = SyncHandler(keys=["key"], callback=handler_2_function)
#Register the handler
asyncraft.register_handler(handler)

...

# Create an async handler without decorator
#First again define the callback function
async def handler_3_function(message):
    print(message)
#Then create the handler
handler = AsyncHandler(keys=["key"], callback=handler_3_function)
#Register the handler
asyncraft.register_handler(handler)
...

Queues

Another major part of Asyncraft are queues. Queues listen to keys and store messages before they are processed further.

from asyncraft import MessageQueue
from asyncraft import Message
import asyncraft
...
#Create a queue which listenes to keys 'Key' and 'Key1'.
#All messages with at least one of those keys will be stored in the queue.
queue = MessageQueue(["Key", "Key1"])
#Register the queue
asyncraft.register_queue(queue)
...
#Get the next message from the queue. If the queue is empty, block until a message is available.
message: Message = queue.get(blocking=True)
...
#Get the next message from the queue in an async context. If the queue is empty, block until a message is available.
message: Message = queue.async_get(blocking=True) 
...

Broadcast and wait for response

The broadcast_and_wait function can be used to send a message and wait for a response.

import asyncraft
from asyncraft import Message
...
# Create a message
message = Message(key='key', value='value')
# Broadcast the message and wait for a response.
# The response will be the first message with the key 'key1' that is received.
# If no response is received within 10 seconds, None will be returned.
response: Message = asyncraft.broadcast_and_wait(message,["key1"], timeout=10)

Examples

The following examples demonstrate how to use Asyncraft.

Ping-Pong

This example demonstrates how to use Asyncraft to create a simple ping-pong system.

import asyncio
import time
import asyncraft


@asyncraft.asyncraft_handler(keys=["Ping"])
def ping_handler_function(message):
    """This is a sync handler that will respond to the Pong handler. It will be executed in a separate thread."""
    print(f"Received {message.key} with value {message.value}")
    time.sleep(1)
    return asyncraft.Message("Pong", message.value + 1)


@asyncraft.asyncraft_handler(keys=["Pong"])
async def pong_handler_function(message):
    """This is an async handler that will respond to the Ping handler. It will be executed in the event loop."""
    print(f"Received {message.key} with value {message.value}")
    await asyncio.sleep(1)
    return asyncraft.Message("Ping", message.value + 1)


async def main():
    asyncraft.broadcast(asyncraft.Message("Ping", 0))
    while True:
        #print("Tick...")
        await asyncio.sleep(1)


if __name__ == "__main__":
    asyncraft.start(main())

Queue

This example demonstrates how to use the MessageQueue class and how one can use it to read and write messages.

import asyncio
import time
import asyncraft
from asyncraft.queues import MessageQueue


async def async_reader(queue: MessageQueue):
    """This function will read messages asynchronously."""
    while True:
        message = await queue.async_get(blocking=True)
        print(f"Reading async {message.key} with value {message.value}")
        await asyncio.sleep(0.1)


def reader(queue: MessageQueue):
    """This function will read messages in another thread."""
    while True:
        message = queue.get(blocking=True)
        print(f"Reading threaded {message.key} with value {message.value}")
        time.sleep(0.1)


async def async_producer():
    """This function will produce messages asynchronously."""
    while True:
        print("Async Producing...")
        asyncraft.broadcast(asyncraft.Message("Key1", "From async producer"))
        await asyncio.sleep(1)


def producer():
    """This function will produce messages synchronously."""
    while True:
        print("Threaded Producing...")
        asyncraft.broadcast(asyncraft.Message("Key", "From thread producer"))
        time.sleep(1)


async def main():
    await asyncio.gather(
        async_reader(queue),
        async_producer(),
        asyncio.to_thread(reader, queue),
        asyncio.to_thread(producer)
    )


if __name__ == "__main__":
    queue = MessageQueue(["Key", "Key1"])
    asyncraft.register_queue(queue)
    asyncraft.start(main())

License

This project is licensed under the terms of the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

asyncraft-0.0.3.tar.gz (9.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

asyncraft-0.0.3-py3-none-any.whl (8.5 kB view details)

Uploaded Python 3

File details

Details for the file asyncraft-0.0.3.tar.gz.

File metadata

  • Download URL: asyncraft-0.0.3.tar.gz
  • Upload date:
  • Size: 9.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.0.0 CPython/3.12.3

File hashes

Hashes for asyncraft-0.0.3.tar.gz
Algorithm Hash digest
SHA256 b274e362821959fd95d8316d1dd51ebfe7b3b270ab48faba90e69d6db5de08e4
MD5 221ef894b9bfb731212b688a26328e33
BLAKE2b-256 f9f07c209b55fbf833fa616e259e3253c0d448b5f6e7e1ac607996c31c026ef6

See more details on using hashes here.

File details

Details for the file asyncraft-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: asyncraft-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 8.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.0.0 CPython/3.12.3

File hashes

Hashes for asyncraft-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 5e70c10a1d7fed9b22375143b864767ab8836f3b71ccd3a01d018a6cb837f120
MD5 1fdb2d9587e33bc6efeff85a375f02ca
BLAKE2b-256 6267e4d8d63152e5dcb91356d8d4ca04e16242b91d23b2efbc65cf44b089e770

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page