Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

django and nats #330

Open
ElonGagarin opened this issue Jul 12, 2022 · 2 comments
Open

django and nats #330

ElonGagarin opened this issue Jul 12, 2022 · 2 comments
Assignees

Comments

@ElonGagarin
Copy link

Hello friends! Thanks for the detailed documentation. But I need advice!
I have a service with a lot of docker images) Some of them work on django - rest_framework, and many of them on asyncio.
I need to communicate between images via http. But part of the communication I wanted to do was through the nuts.

Connecting nuts to those images that are built on asyncio was no problem, everything works great!

Has anyone connected nuts to django?

If all asynchronous requests are wrapped in a loop, they often fall off. I think it's Django's fault and of course my clumsy hands :) Below I will give what I have now and I don't like it...

The client that I made in django, and I import an instance of the class of this client where I want to send a message through the nats

So, please advise how to make friends between django and nats.

class NatsClient():
    def __init__(self, token, servers):
        self.token: str = token
        self.servers: str = servers
        self.loop_publish = asyncio.new_event_loop()
        self.loop_connection = asyncio.new_event_loop()
        self.start_nats()

    async def disconnected_cb(self):
        logging.info('NATS: Got disconnected!')

    async def reconnected_cb(self):
        logging.info(
            f'NATS: Got reconnected to {self.nc.connected_url.netloc}')

    async def error_cb(self, e):
        logging.info(f'NATS: There was an error: {e}')

    async def closed_cb(self):
        logging.info('NATS: Connection is closed')

    def start_nats(self):
        try:
            self.nc = self.loop_connection.run_until_complete(
                nats.connect(servers=self.servers,
                             token=self.token,
                             error_cb=self.error_cb,
                             reconnected_cb=self.reconnected_cb,
                             disconnected_cb=self.disconnected_cb,
                             closed_cb=self.closed_cb,
                             max_reconnect_attempts=1,
                             reconnect_time_wait=1,
                             ping_interval=3,
                             max_outstanding_pings=3,
                             connect_timeout=1,
                             )
            )
            logging.info(f'application NATS started')
        except:
            logging.info(f'Nats: no servers available for connection')

    async def publish(self, subscribe, data):
        text = json.dumps(data).encode('utf-8')
        await self.nc.publish(subscribe, text)

    def close(self):
        self.loop_connection.run_until_complete(self.nc.close())
        self.loop_connection.run_until_complete(self.nc.drain())

    def publish_not_async(self, subscribe, data):
        self.loop_publish.run_until_complete(self.publish(subscribe, data))


nats_client = NatsClient(
    token=NATS_AUTH_TOKEN,
    servers=f'{NATS_HOST}:{NATS_PORT}'
)
@ljluestc
Copy link

Here's a simplified example of how you might structure your code using Django Channels:

  1. Install Django Channels if you haven't already:

    pip install channels
  2. Modify your NatsClient class to work within an async context and be compatible with Django Channels:

import asyncio
from nats.aio import connect, errors

class NatsClient:
    def __init__(self, token, servers):
        self.token = token
        self.servers = servers
        self.loop = asyncio.get_event_loop()
        self.start_nats()

    async def error_cb(self, e):
        print(f'NATS: There was an error: {e}')

    async def connected_cb(self):
        print('NATS: Connected!')

    async def start_nats(self):
        try:
            self.nc = await connect(
                servers=self.servers,
                token=self.token,
                error_cb=self.error_cb,
                connected_cb=self.connected_cb,
                loop=self.loop
            )
            print('Application NATS started')
        except errors.ErrNoServers:
            print('NATS: No servers available for connection')

    async def publish(self, subscribe, data):
        text = json.dumps(data).encode('utf-8')
        await self.nc.publish(subscribe, text)

    async def close(self):
        await self.nc.close()

nats_client = NatsClient(
    token=NATS_AUTH_TOKEN,
    servers=f'{NATS_HOST}:{NATS_PORT}'
)
  1. Use Django Channels to integrate your NATS client with Django. Create a Django consumer that can handle asynchronous operations:
# consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer

class NatsConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        data = json.loads(text_data)
        await nats_client.publish(data['subject'], data['message'])
  1. Configure your Django project to use Django Channels for WebSocket handling. Refer to the Django Channels documentation for more information on setting up Django Channels in your project.

@RussellLuo
Copy link

RussellLuo commented Jun 20, 2024

I encountered a similar issue and ended up writing a sidecar service in Go (hats), which makes it easy for Django/DRF (or other Web) applications to communicate with NATS using HTTP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants