async def send(self, channel, message): """ Send a message onto a (general or specific) channel. """ # Typecheck assert isinstance(message, dict), "message is not a dict" assert self.valid_channel_name(channel), "Channel name not valid" # Make sure the message does not contain reserved keys assert "__asgi_channel__" not in message # If it's a process-local channel, strip off local part and stick full name in message channel_non_local_name = channel if "!" in channel: message = dict(message.items()) message["__asgi_channel__"] = channel channel_non_local_name = self.non_local_name(channel) # Write out message into expiring key (avoids big items in list) channel_key = self.prefix + channel_non_local_name # Pick a connection to the right server - consistent for specific # channels, random for general channels if "!" in channel: index = self.consistent_hash(channel) else: index = next(self._send_index_generator) async with self.connection(index) as connection: # Check the length of the list before send # This can allow the list to leak slightly over capacity, but that's fine. if await connection.llen(channel_key) >= self.get_capacity(channel): raise ChannelFull() # Push onto the list then set it to expire in case it's not consumed await connection.rpush(channel_key, self.serialize(message)) await connection.expire(channel_key, int(self.expiry))
async def send(self, channel, asgi_channel, message): """ Send a message onto a (generic or specific) channel. This publishes through RabbitMQ even when sending from localhost to localhost. This gives approximate global ordering. Usage: connection.send({'foo': 'bar'}) """ message["__asgi_channel__"] = asgi_channel message = msgpack.packb(message, use_bin_type=True) queue_name = channel_to_queue_name(asgi_channel) # Publish with publisher_confirms=True. Assume the server is configured # with `overflow: reject-publish`, so we get a basic.nack if the queue # length is exceeded. try: logger.debug("publish %r on %s", message, queue_name) await channel.publish(message, "", queue_name) except PublishFailed: raise ChannelFull() logger.debug("ok")
async def send(self, channel: str, message: Scope) -> None: """ Send a message onto a (general or specific) channel. """ # Typecheck assert isinstance(message, dict), "message is not a dict" assert self.valid_channel_name(channel), "Channel name not valid" # If it's a process-local channel, strip off local part and stick full name in message assert "__asgi_channel__" not in message queue = self.channels.setdefault(channel, asyncio.Queue()) # Are we full if queue.qsize() >= self.capacity: raise ChannelFull(channel) # Add message await queue.put((time.time() + self.expiry, deepcopy(message)))