django / channels

Developer-friendly asynchrony for Django

Home Page:https://channels.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

eschuma-prog opened this issue · comments

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)

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.

@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.

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?