#python-3.x #websocket #redis #django-channels
#python-3.x #websocket #redis #django-каналы
Вопрос:
consumer.py
# accept websocket connection
def connect(self):
self.accept()
# Receive message from WebSocket
def receive(self, text_data):
text_data_json = json.loads(text_data)
command = text_data_json['command']
job_id = text_data_json['job_id']
if command == 'subscribe':
self.subscribe(job_id)
elif command == 'unsubscribe':
self.unsubscribe(job_id)
else:
self.send({
'error': 'unknown command'
})
# Subscribe the client to a particular 'job_id'
def subscribe(self, job_id):
self.channel_layer.group_add(
'job_{0}'.format(job_id),
self.channel_name
)
# call this method from rest api to get the status of a job
def send_job_notification(self, message, job_id):
channel_layer = get_channel_layer()
group_name = 'job_{0}'.format(job_id)
channel_layer.group_send(
group_name,
{
"type": "send.notification",
"message": message,
}
)
# Receive message from room group
def send_notification(self, event):
message = event['message']
# Send message to WebSocket
self.send(text_data=json.dumps(
message))
В приведенном выше коде то, что я пытаюсь сделать, это подключить клиентов к сокету и подписать клиентов на определенный «job_id», создав группу с именем «job_1», используя метод «subscribe» и добавив ее на уровень канала. Создание групп происходит динамично.
Я использую приведенное ниже «простое клиентское расширение websocket» от Google для подключения к вышеупомянутому websocket. Я могу установить соединение с websocket и отправить ему запрос, как показано на рисунке ниже.
Теперь, поскольку клиент подключен и подписан на определенный «job_id», я использую «Postman» для отправки уведомления вышеупомянутому подключенному клиенту (simple websocket client extension), подписанному на определенный «job_id», передавая job_id в запросе, как выделено желтым ниже.
когда я делаю post в «REST-API», я вызываю метод «send_job_notification (self, message, job_id)» для «consumer.py «файл вместе с «job_id» как «1», показанный на рисунке ниже желтым цветом
После выполнения всего этого я не вижу никакого сообщения, отправленного подключенному клиенту, подписанному на «job_id» из вызова «REST-API».
Любая помощь была бы высоко оценена, поскольку она затягивается на долгое время.
Редактировать:
спасибо за предложение, знаю, что стоит сделать метод как «@staticmethod», но знаю, как мне заставить API отправлять обновления статуса задания подключенным клиентам, потому что мои длительно выполняющиеся задания будут выполняться в каком-то процессе и отправлять сообщения об обновлении обратно на серверную часть через REST-API, а затем обновления должны быть отправлены правильному клиенту (через websockets).
Мой вызов API для потребителя сокета выглядит следующим образом:
from websocket_consumer import consumers
class websocket_connect(APIView):
def post(self, request, id):
consumers.ChatConsumer.send_job_notification("hello",id)
Мой код пользователя сокета выглядит следующим образом:
Редактировать
`CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("localhost", 6379)],
},
},
}`
Как вы можете видеть, служба ‘Redis’ также запущена
Редактировать-1
Комментарии:
1. Можете ли вы опубликовать код в REST API, который вызывает метод потребителя?
2. размещение скриншотов здесь настоятельно не рекомендуется, поскольку людям сложно скопировать ваш код и опробовать его. Пожалуйста, разместите вместо этого форматированный код
3. Опять же, мне трудно понять ваш вопрос. Вы хотите отправлять обновления статуса задания? как вы получаете обновления? Вы можете отправить их из процесса, выполняющего задание, вызвав send_job_notification и передав статус / ход выполнения задания в виде сообщения. Но опять же, я, вероятно, не правильно вас понял
4. Я попытался отформатировать код Ken, но редактор выдавал ошибку, поэтому я добавил скриншот. Да, вы правы, я получаю обновления от процесса, выполняющего задание, и эти обновления передаются API, а затем API вызывает ‘send_job_notification’, передавая ‘message’ и ‘job_id’ в качестве параметров для отправки уведомлений о задании подключенным клиентам ‘websocket’. Надеюсь, вы поняли.
5. Отлично. Итак, в чем тогда ваш вопрос, если вы уже поняли это? проблема в ошибках на скриншоте? как вы можете видеть, у вас есть extra `, который необходимо удалить, и пакет json также необходимо импортировать
Ответ №1:
Вы не можете вызвать метод в consumer напрямую из внешнего кода, потому что вам нужно подключить конкретный экземпляр consumer к вашему клиенту. Это работа канального уровня, достигаемая с помощью системы передачи сообщений или брокера, такого как reddis. Из того, что я вижу, вы уже движетесь в правильном направлении, за исключением того, что send_job_notification
это метод экземпляра, который потребует создания экземпляра потребителя. Вместо этого сделайте его статическим методом, чтобы вы могли вызывать его напрямую, без экземпляра потребителя
@staticmethod
def send_job_notification(message, job_id):
channel_layer = get_channel_layer()
group_name = 'job_{0}'.format(job_id)
channel_layer.group_send(
group_name,
{
"type": "send.notification",
"message": message,
}
И в вашем представлении API вы можете просто вызвать его как:
ChatConsumer.send_job_notification(message, job_id)
Комментарии:
1. Пожалуйста, добавьте код к исходному сообщению и хорошо отформатируйте его, чтобы его можно было прочитать. Также не публикуйте скриншоты ошибок. Вместо этого опубликуйте обратную трассировку, поскольку она не читается таким образом
2. Кен, как и предполагалось, я отредактировал исходное сообщение, можете ли вы, пожалуйста, взглянуть. Я отметил изменения в разделе «Редактировать»: