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

Channel Layer's group_send() Not Working When Called From Django View #2079

Open
eschuma-prog opened this issue Mar 7, 2024 · 4 comments
Open

Comments

@eschuma-prog
Copy link

eschuma-prog commented Mar 7, 2024

I can redirect this to through the appropriate channels if need but wanted to make sure this wasn't a bug of any sort prior.
Currently I'm running into a issue when doing a call of group_send from my Django view that is synchronous to a AsyncJsonWebsocketConsumer's async method called send_update. async_to_sync is used appropriately as shown below. When called outside of the view in something like a management command the group_send works as expected and the consumer enacts the send_update method, however, when called within the create method nothing is sent to my channel. Is this intended behavior?

My system is running with RedisChannelLayers along with daphne

Relevant pip freeze information:
channels==4.0.0
channels-redis==4.2.0
daphne==4.1.0

In all instances the channel layer exists and there are no errors outputted by the group_send async_to_sync call.

# Assume imports...

# Example view: 
def create(self, request):
    #Nothing is sent to my channel here
    async_to_sync(get_channel_layer().group_send)(
        "group1",
        {
            "type": "send_update",
            "message": "hi"
        }
    )

# Example consumer:
class ConsumerA(AsyncJsonWebsocketConsumer):
  async def connect(self):
          """ Establishes the channel connection and sets up a group """
  
          await self.channel_layer.group_add("group1", self.channel_name)
          await self.accept()

  async def send_update(self, event):
          """ Send updates to front-end """
  
          message = event['message']
          await self.send_json(message)

# Example management command:
class Command(BaseCommand):
    def handle(self, *args, **options):
        try:
            # Works perfectly fine here
            async_to_sync(get_channel_layer().group_send)(
                "group1",
                {
                    "type": "send_update",
                    "message": "hi"
                },
            )
        except Exception as e:
            print(e)
@carltongibson
Copy link
Member

That looks like it should be working at first glance. You'll need to dig-in here: can you debug the group send call? What's not working? (Do you have a Redis connection? Is anything posted? Is the event loop running, etc.)

There's not enough here for me to say anything more concrete I'm afraid.

@eschuma-prog
Copy link
Author

@carltongibson For more clarification there is a Redis connection when getting the channel_layer. However, I cannot retrieve the event loop (states that one doesn't exist when checking with asyncio) while handling HTTP Requests through my create method in the view. This is while my websocket connection is still live and I can fire off the management commands separately during the create call handling just fine and receive the management command message on the other end. From the looks of it, inside of the RedisChannelLayer.group_send() it does not get connections through self.connection() because asyncio.get_running_loop() is not returning an active loop. So the biggest question would be why isn't the websocket event loop available within the context of the view.

@carltongibson
Copy link
Member

From the looks of it, inside of the RedisChannelLayer.group_send() it does not get connections through self.connection() because asyncio.get_running_loop() is not returning an active loop.

Could you provide a minimal reproduce?

@weekman123
Copy link

Same problem as you , the functions in views.py cant using the
async_to_sync(channel_layer.group_send)(
name,
{
"type": "pullback.handle.message",
"groupId": group.groupId,
"pullback": grouper_id,
"id_type": 'grouper'
}
)
to active the function async def pullback_handle_message(self, event): in class MyConsumer(AsyncWebsocketConsumer)

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

3 participants