RabbitMQ--基础--10.2--死信队列

2023-11-05

RabbitMQ–基础–10.2–死信队列


1、死信队列(DLX queue)

  1. 当消息在一个队列中变成死信之后,它能重新被发送到另一个交换机中,这个交换机就是 死信交换机,绑定 死信交换机(DLX Exchange) 的队列就称之为死信队列
  2. 死信队列同其他的队列一样都是普通的队列。
  3. 在RabbitMQ中并没有特定的"死信队列"类型,而是通过配置,将其实现。
    1. 设置死信队列需要设置以下2个属性
      1. 交换机 x-dead-letter-exchange
      2. 路由键 x-dead-letter-routing-key

在这里插入图片描述

2、设置死信队列

  1. 当我们在创建一个业务的交换机和队列的时候,可以配置参数,指明另一个队列为当前队列的死信队列。
  2. 当消息"死信"后,会被自动路由到DLX Exchange的queue中
    在这里插入图片描述

在这里插入图片描述

3、消息变成死信有这几种情况

  1. 消费者对broker应答nack,并且消息禁止重回队列。
    1. 应答nack
      1. basic.reject or basic.nack
    2. 消息禁止重回队列
      1. requeue=false
  2. 消费者对broker应答nack,允许重回队列,但是达到的retry重新入队的上限次数
  3. 消息的TTL过期(Time To Live):存活时间已经过期
  4. Queue队列长度已达上限。
    1. 队列满,queue的"x-max-length"参数

4、死信队列的应用场景

  1. 处理异常情况
    1. 重要的业务队列如果失败,就需要重新将消息用另一种业务逻辑处理。因为消息放到 另一个队列(A)里面,只要处理A队列的内容就行
  2. 搭配 TTL 模拟延迟队列
  3. 如果是正常的业务逻辑故意让消息中不合法的值失败,就不需要死信

5、代码

5.1、结构

在这里插入图片描述

5.2、代码架构图

在这里插入图片描述

5.3、死信队列的实现

  1. TTL过期
  2. 队列达到最大长度
  3. 消息被拒

5.3.1、TTL过期

 package com.example.rabbitmq03.business.dead_queue.demo1;

import com.example.rabbitmq03.business.confirm.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;

/**
 * 死信队列实战 生产者
 */
public class Producer {
    
    // 定义交换机名称
    public static final String NORMAL_EXCHANGE = "normal_exchange";
    public static final String DEAD_EXCHANGE = "dead_exchange";
    // 定义队列名称
    public static final String NORMAL_QUEUE = "normal_queue";
    public static final String DEAD_QUEUE = "dead_queue";

    // 设置RoutingKey
    public static final String NORMAL_RoutingKey = "zhangsan";
    public static final String DEAD_RoutingKey = "lisi";


    public static void main(String[] args) throws Exception {
        // 1. 获取连接
        Connection connection = RabbitMqUtil.getConnection("生产者");
        // 2. 通过连接获取通道 Channel
        Channel channel = connection.createChannel();

        setConig(channel);


        // 开启发布确认
        channel.confirmSelect();
        
        ConcurrentSkipListMap<Long, String> map = new ConcurrentSkipListMap<>();
        // 消息发布确认成功回调函数
        ConfirmCallback ackCallback = (deliveryTag, multiple) -> {
            if (multiple) {
                ConcurrentNavigableMap<Long, String> confirmed = map.headMap(deliveryTag);
                confirmed.clear();
            } else {
                map.remove(deliveryTag);
            }
            System.out.println("消息发布确认成功:" + deliveryTag);
        };
        
        // 消息发布确认失败回调函数
        ConfirmCallback nackCallback = (deliveryTag, multiple) -> {
            System.out.println("消息发布确认失败:" + deliveryTag);
        };
        
        // 准备确认监听器
        channel.addConfirmListener(ackCallback, nackCallback);
        
        String message = "Hello Dead Queue";
        
        // 死信消息 设置TTL时间(过期时间) 单位:ms,这里5秒就过期
        AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("5000").build();
        
        // 发送消息
        channel.basicPublish(NORMAL_EXCHANGE, NORMAL_RoutingKey, properties, message.getBytes());
        map.put(channel.getNextPublishSeqNo(), message);
        
        System.out.println("发出消息:" + message);
        
    }

    //配置交换机,队列,路由键信息
    public static void setConig(Channel channel) throws Exception {
        // 声明普通交换机
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        // 声明死信交换机
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);
        
        Map<String, Object> arguments = new HashMap<>();
        // 设置死信交换机
        arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);
        // 设置死信RoutingKey
        arguments.put("x-dead-letter-routing-key", DEAD_RoutingKey);
        
        // 声明普通队列
        channel.queueDeclare(NORMAL_QUEUE, true, false, false, arguments);
        // 声明死信队列
        channel.queueDeclare(DEAD_QUEUE, true, false, false, null);
        
        // 绑定交换机与队列
        channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, NORMAL_RoutingKey);
        channel.queueBind(DEAD_QUEUE, DEAD_EXCHANGE, DEAD_RoutingKey);
    }
}
 package com.example.rabbitmq03.business.dead_queue.demo1;

import com.example.rabbitmq03.business.confirm.RabbitMqUtil;
import com.rabbitmq.client.*;

import java.util.HashMap;
import java.util.Map;

/**
 * 死信队列实战: TTL过期 消费者01
 */
public class Consumer {
    // 定义队列名称
    public static final String NORMAL_QUEUE = "normal_queue";
    
    public static void main(String[] args) throws Exception {
        // 1. 获取连接
        Connection connection = RabbitMqUtil.getConnection("生产者");
        // 2. 通过连接获取通道 Channel
        Channel channel = connection.createChannel();
        
        System.out.println("Consumer等待接收消息。。。");
        
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("Consumer接收到的消息:" + new String(message.getBody(), "UTF-8"));
            // 手动应答
            channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
        };
        
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消息消费失败");
        };
        // 消费消息
        channel.basicConsume(NORMAL_QUEUE, false, deliverCallback, cancelCallback);
    }
}
package com.example.rabbitmq03.business.dead_queue.demo1;

import com.example.rabbitmq03.business.confirm.RabbitMqUtil;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;

/**
 * 死信队列实战: TTL过期
 * 死信消费者
 */
public class DeadConsumer {

    public static final String DEAD_QUEUE = "dead_queue";

    public static void main(String[] args) throws Exception{
        // 1. 获取连接
        Connection connection = RabbitMqUtil.getConnection("生产者");
        // 2. 通过连接获取通道 Channel
        Channel channel = connection.createChannel();

        System.out.println("DeadConsumer等待接收消息。。。");

        DeliverCallback deliverCallback = ( consumerTag,  message) ->{
            System.out.println("DeadConsumer接收到的消息:"+new String(message.getBody(),"UTF-8"));
            //手动应答
            channel.basicAck(message.getEnvelope().getDeliveryTag(),false);
        };

        CancelCallback cancelCallback = consumerTag ->{
            System.out.println("消息消费失败");
        };
        //消费消息
        channel.basicConsume(DEAD_QUEUE,false,deliverCallback,cancelCallback);
    }
}
  1. 先启动Producer
  2. 再启动DeadConsumer
    在这里插入图片描述

5.3.2、队列达到最大长度

package com.example.rabbitmq03.business.dead_queue.demo2;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;

import com.example.rabbitmq03.business.confirm.RabbitMqUtil;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmCallback;
import com.rabbitmq.client.Connection;

/**
 * 死信队列实战 生产者
 */
public class Producer {
    
    // 定义交换机名称
    public static final String NORMAL_EXCHANGE = "normal_exchange2";
    public static final String DEAD_EXCHANGE = "dead_exchange2";
    // 定义队列名称
    public static final String NORMAL_QUEUE = "normal_queue2";
    public static final String DEAD_QUEUE = "dead_queue2";
    
    // 设置RoutingKey
    public static final String NORMAL_RoutingKey = "zhangsan2";
    public static final String DEAD_RoutingKey = "lisi2";
    
    public static void main(String[] args) throws Exception {
        // 1. 获取连接
        Connection connection = RabbitMqUtil.getConnection("生产者");
        // 2. 通过连接获取通道 Channel
        Channel channel = connection.createChannel();
        
        setConig(channel);
        
        // 开启发布确认
        channel.confirmSelect();
        
        ConcurrentSkipListMap<Long, String> map = new ConcurrentSkipListMap<>();
        // 消息发布确认成功回调函数
        ConfirmCallback ackCallback = (deliveryTag, multiple) -> {
            if (multiple) {
                ConcurrentNavigableMap<Long, String> confirmed = map.headMap(deliveryTag);
                confirmed.clear();
            } else {
                map.remove(deliveryTag);
            }
            System.out.println("消息发布确认成功:" + deliveryTag);
        };
        
        // 消息发布确认失败回调函数
        ConfirmCallback nackCallback = (deliveryTag, multiple) -> {
            System.out.println("消息发布确认失败:" + deliveryTag);
        };
        
        // 准备确认监听器
        channel.addConfirmListener(ackCallback, nackCallback);
        
        for (int i = 0; i < 11; i++) {
            String message = "Hello Dead Queue" + i;
            // 发送消息
            channel.basicPublish(NORMAL_EXCHANGE, NORMAL_RoutingKey, null, message.getBytes());
            map.put(channel.getNextPublishSeqNo(), message);
            System.out.println("发出消息:" + message);
        }
        
    }
    
    // 配置交换机,队列,路由键信息
    public static void setConig(Channel channel) throws Exception {
        // 声明普通交换机
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        // 声明死信交换机
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);
        
        Map<String, Object> arguments = new HashMap<>();
        // 设置死信交换机
        arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);
        // 设置死信RoutingKey
        arguments.put("x-dead-letter-routing-key", DEAD_RoutingKey);
        // 设置正常队列的长度
        arguments.put("x-max-length", 6);
        // 声明普通队列
        channel.queueDeclare(NORMAL_QUEUE, true, false, false, arguments);
        // 声明死信队列
        channel.queueDeclare(DEAD_QUEUE, true, false, false, null);
        
        // 绑定交换机与队列
        channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, NORMAL_RoutingKey);
        channel.queueBind(DEAD_QUEUE, DEAD_EXCHANGE, DEAD_RoutingKey);
        
    }
}

package com.example.rabbitmq03.business.dead_queue.demo2;

import com.example.rabbitmq03.business.confirm.RabbitMqUtil;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;

/**
 * 死信队列实战: TTL过期
 * 死信消费者
 */
public class DeadConsumer {

    public static final String DEAD_QUEUE = "dead_queue2";

    public static void main(String[] args) throws Exception{
        // 1. 获取连接
        Connection connection = RabbitMqUtil.getConnection("生产者");
        // 2. 通过连接获取通道 Channel
        Channel channel = connection.createChannel();

        System.out.println("DeadConsumer等待接收消息。。。");

        DeliverCallback deliverCallback = ( consumerTag,  message) ->{
            System.out.println("DeadConsumer接收到的消息:"+new String(message.getBody(),"UTF-8"));
            //手动应答
            channel.basicAck(message.getEnvelope().getDeliveryTag(),false);
        };

        CancelCallback cancelCallback = consumerTag ->{
            System.out.println("消息消费失败");
        };
        //消费消息
        channel.basicConsume(DEAD_QUEUE,false,deliverCallback,cancelCallback);
    }
}
package com.example.rabbitmq03.business.dead_queue.demo2;

import com.example.rabbitmq03.business.confirm.RabbitMqUtil;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;

/**
 * 死信队列实战: TTL过期 消费者01
 */
public class Consumer {
    // 定义队列名称
    public static final String NORMAL_QUEUE = "normal_queue2";
    
    public static void main(String[] args) throws Exception {
        // 1. 获取连接
        Connection connection = RabbitMqUtil.getConnection("生产者");
        // 2. 通过连接获取通道 Channel
        Channel channel = connection.createChannel();
        
        System.out.println("Consumer等待接收消息。。。");
        
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("Consumer接收到的消息:" + new String(message.getBody(), "UTF-8"));
            // 手动应答
            channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
        };
        
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消息消费失败");
        };
        // 消费消息
        channel.basicConsume(NORMAL_QUEUE, false, deliverCallback, cancelCallback);
    }
}

在这里插入图片描述

5.3.3、消息被拒

package com.example.rabbitmq03.business.dead_queue.demo3;

import com.example.rabbitmq03.business.confirm.RabbitMqUtil;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;

/**
 * 死信队列实战: TTL过期 消费者01
 */
public class Consumer {
    // 定义队列名称
    public static final String NORMAL_QUEUE = "normal_queue3";
    
    public static void main(String[] args) throws Exception {
        // 1. 获取连接
        Connection connection = RabbitMqUtil.getConnection("生产者");
        // 2. 通过连接获取通道 Channel
        Channel channel = connection.createChannel();
        
        System.out.println("Consumer等待接收消息。。。");
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String msg = new String(message.getBody(), "UTF-8");
            if (msg.equals("Hello Dead Queue1")) {
                // 拒绝
                System.out.println("Consumer接收到的消息:" + msg + ",此消息被拒绝");
                channel.basicReject(message.getEnvelope().getDeliveryTag(), false);
            } else {
                System.out.println("Consumer接收到的消息:" + msg);
                // 手动应答
                channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
            }
        };
        
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消息消费失败");
        };
        // 消费消息
        channel.basicConsume(NORMAL_QUEUE, false, deliverCallback, cancelCallback);
    }
}
package com.example.rabbitmq03.business.dead_queue.demo3;

import com.example.rabbitmq03.business.confirm.RabbitMqUtil;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;

/**
 * 死信队列实战: TTL过期 死信消费者
 */
public class DeadConsumer {
    
    public static final String DEAD_QUEUE = "dead_queue3";
    
    public static void main(String[] args) throws Exception {
        // 1. 获取连接
        Connection connection = RabbitMqUtil.getConnection("生产者");
        // 2. 通过连接获取通道 Channel
        Channel channel = connection.createChannel();
        
        System.out.println("DeadConsumer等待接收消息。。。");
        
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("DeadConsumer接收到的消息:" + new String(message.getBody(), "UTF-8"));
            // 手动应答
            channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
        };
        
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消息消费失败");
        };
        // 消费消息
        channel.basicConsume(DEAD_QUEUE, false, deliverCallback, cancelCallback);
    }
}
package com.example.rabbitmq03.business.dead_queue.demo3;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;

import com.example.rabbitmq03.business.confirm.RabbitMqUtil;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmCallback;
import com.rabbitmq.client.Connection;

/**
 * 死信队列实战 生产者
 */
public class Producer {
    
    // 定义交换机名称
    public static final String NORMAL_EXCHANGE = "normal_exchange3";
    public static final String DEAD_EXCHANGE = "dead_exchange3";
    // 定义队列名称
    public static final String NORMAL_QUEUE = "normal_queue3";
    public static final String DEAD_QUEUE = "dead_queue3";
    
    // 设置RoutingKey
    public static final String NORMAL_RoutingKey = "zhangsan3";
    public static final String DEAD_RoutingKey = "lisi3";
    
    public static void main(String[] args) throws Exception {
        // 1. 获取连接
        Connection connection = RabbitMqUtil.getConnection("生产者");
        // 2. 通过连接获取通道 Channel
        Channel channel = connection.createChannel();
        
        setConig(channel);
        
        // 开启发布确认
        channel.confirmSelect();
        
        ConcurrentSkipListMap<Long, String> map = new ConcurrentSkipListMap<>();
        // 消息发布确认成功回调函数
        ConfirmCallback ackCallback = (deliveryTag, multiple) -> {
            if (multiple) {
                ConcurrentNavigableMap<Long, String> confirmed = map.headMap(deliveryTag);
                confirmed.clear();
            } else {
                map.remove(deliveryTag);
            }
            System.out.println("消息发布确认成功:" + deliveryTag);
        };
        
        // 消息发布确认失败回调函数
        ConfirmCallback nackCallback = (deliveryTag, multiple) -> {
            System.out.println("消息发布确认失败:" + deliveryTag);
        };
        
        // 准备确认监听器
        channel.addConfirmListener(ackCallback, nackCallback);
        
        for (int i = 0; i < 5; i++) {
            String message = "Hello Dead Queue" + i;
            // 发送消息
            channel.basicPublish(NORMAL_EXCHANGE, NORMAL_RoutingKey, null, message.getBytes());
            map.put(channel.getNextPublishSeqNo(), message);
            System.out.println("发出消息:" + message);
        }
        
    }
    
    // 配置交换机,队列,路由键信息
    public static void setConig(Channel channel) throws Exception {
        // 声明普通交换机
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        // 声明死信交换机
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);
        
        Map<String, Object> arguments = new HashMap<>();
        // 设置死信交换机
        arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);
        // 设置死信RoutingKey
        arguments.put("x-dead-letter-routing-key", DEAD_RoutingKey);
        // // 设置正常队列的长度
        // arguments.put("x-max-length", 6);
        // 声明普通队列
        channel.queueDeclare(NORMAL_QUEUE, true, false, false, arguments);
        // 声明死信队列
        channel.queueDeclare(DEAD_QUEUE, true, false, false, null);
        
        // 绑定交换机与队列
        channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, NORMAL_RoutingKey);
        channel.queueBind(DEAD_QUEUE, DEAD_EXCHANGE, DEAD_RoutingKey);
        
        // 声明普通交换机
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        // 声明死信交换机
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);
        
    }
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RabbitMQ--基础--10.2--死信队列 的相关文章

  • RabbitMQ 用户在预先创建的队列上发布/订阅的权限

    我有一个用例 我需要创建一个用户并授予他仅在现有队列上发布 订阅的权限 这是一个示例 虚拟主机 mainvhost 对于所有用户都相同 在虚拟主机内 我有 A foo 和 Q bar 队列 用户 foo 只能发布 订阅到 Q foo 用户
  • Rails:如何从服务或队列中监听/拉取?

    大多数 Rails 应用程序的工作方式都是等待来自客户端的请求 然后发挥其作用 但是 如果我想将 Rails 应用程序用作微服务架构的一部分 例如 并进行一些异步通信 服务 A 将事件发送到 Kafka 或 RabbitMQ 队列 而服务
  • 在 django 中使用 pika 的 Rabbitmq 监听器

    我有一个 django 应用程序 我想使用来自rabbit mq 的消息 我希望监听器在启动 django 服务器时开始使用 我正在使用 pika 库连接到rabbitmq 提供一些代码示例确实会有帮助 首先 您需要在 django 项目开
  • 为什么 Celery 工作人员给出“OSError:套接字已关闭”

    我的与rabbitMQ一起工作的celery工作人员在工作几分钟后不断给我一个套接字错误 见下文 我想知道问题的主要原因是什么 我认为这可能是防火墙 但是 禁用防火墙并没有解决问题 我正在 Windows 10 机器上工作 C Users
  • 如何在 celery 内为每个用户生成队列?

    因此 我尝试将 Web 请求中的阻塞内容移至后台任务并利用队列 我对消息传递和发布 订阅也很陌生 用户将数据推送到那里并进行处理 稍后用户会收到相关通知 我为此做了一个 celery 设置 发现它不能满足我为每个用户分配自己的任务的专用队列
  • 如何根据条件限制并发消息消耗

    场景 我已经简化了事情 许多最终用户可以从前端 Web 应用程序 生产者 开始工作 繁重的工作 例如渲染大型 PDF 这些作业被发送到单个持久的 RabbitMQ 队列 许多工作应用程序 消费者 处理这些作业并将结果写回到数据存储中 这个相
  • 保持鼠兔 BlockingConnection 存活而不禁用心跳

    我正在使用 pika 0 10 0 和 python 2 7 版本开发 RabbitMQ 消费者 在我的消费者客户端中 我有一个根据输入消息运行一段时间的进程 时间可能从 3 到 40 分钟不等 我不想禁用心跳 相反 我正在寻找一些回滚机制
  • 何时使用 RabbitMQ 铲子以及何时使用 Federation 插件?

    对于我工作的公司 我们希望使用 RabbitMQ 作为我们的主要消息总线 我们的想法是 每个应用程序都使用自己的虚拟主机进行内部通信 并且通过 shovel 或联合插件 我们可以在多个虚拟主机 甚至可能是多台机器 非集群 之间共享某些类型的
  • 如何在nodejs中验证rabbitmq?

    错误 握手被服务器终止 403 ACCESS REFUSED 消息 ACCESS REFUSED 使用身份验证拒绝登录 旋转机制平原 有关详细信息 请参阅代理日志文件 我单独尝试了 authMechanism PLAIN AMQPLAIN
  • Django、RabbitMQ 和 Celery - 为什么在我更新开发中的 Django 代码后,Celery 会运行旧版本的任务?

    所以我有一个 Django 应用程序 它偶尔会向 Celery 发送任务以进行异步执行 我发现 当我在开发中处理代码时 Django 开发服务器知道如何自动检测代码何时发生更改 然后重新启动服务器 以便我可以看到我的更改 然而 我的应用程序
  • 为什么需要消息队列来与 Web 套接字聊天?

    我在互联网上看到了很多使用 Web 套接字和 RabbitMQ 进行聊天的示例 https github com videlalvaro rabbitmq chat https github com videlalvaro rabbitmq
  • MongoDB 架构设计 - 实时聊天

    我正在启动一个项目 我认为该项目特别适合 MongoDB 因为它提供的速度和可扩展性 我目前感兴趣的模块是与实时聊天有关的 如果我要在传统的 RDBMS 中执行此操作 我会将其分为 频道 一个频道有很多用户 用户 一个用户有一个频道但有多条
  • Celery 任务状态取决于 CELERY_TASK_RESULT_EXPIRES

    据我所知 任务状态完全取决于 CELERY TASK RESULT EXPIRES 设置的值 如果我在任务完成执行后检查此间隔内的任务状态 则返回的状态为 AsyncResult task id state 是正确的 如果没有 状态将不会更
  • 死信交换 RabbitMQ 丢弃消息

    我正在尝试在 RabbitMQ 中实现 dlx 队列 场景很简单 我有 2 个队列 1 活着 2 死亡 x dead letter exchange 立即 x message ttl 5000 以及 立即 交换 这必然是 1 活着 我尝试运
  • 如何使用 Celery、RabbitMQ 和 Django 确保每个用户的任务执行顺序?

    我正在运行 Django Celery 和 RabbitMQ 我想要实现的是确保与一个用户相关的任务按顺序执行 具体来说 一次执行一个 我不希望每个用户执行任务并发 每当为用户添加新任务时 它应该取决于最近添加的任务 如果此类型的任务已为此
  • 使用 RabbitMq 锁定和批量获取消息

    我正在尝试以一种更非常规的方式使用 RabbitMq 尽管此时我可以根据需要选择任何其他消息队列实现 消费者不会将 Rabbit 推送消息留给我的消费者 而是连接到一个队列并获取一批 N 条消息 在此期间它会消费一些消息 并可能拒绝一些消息
  • Celery 与rabbitmq 创建结果多个队列

    我已经用 RabbitMQ 安装了 Celery 问题是 对于返回的每个结果 Celery 都会在 Rabbit 中创建队列 并在交换 celeryresults 中使用任务 ID 我仍然想得到结果 但在一个队列上 我的芹菜配置 from
  • RabbitMQ Java 客户端自动重新连接

    当我的应用程序失去与 RabbitMQ 的连接时 我将其连接工厂设置为自动尝试并重新连接 ConnectionFactory factory new ConnectionFactory factory setUsername usernam
  • AMQPRuntimeException:读取数据时出错。收到 0 而不是预期的 7 字节

    它曾经有效 但现在不再有效了 我正在使用 php amqplib 和 RabbitMQ 当我尝试创建新的 AMQP 连接时 connection new AMQPConnection localhost 5672 username pass
  • 将 sensu-client 连接到服务器时 AMQP 连接的 bad_header

    我已经安装了 sensu 和厨师社区食谱 但是 sensu客户端无法连接到服务器 导致rabbitmq连接错误 尝试连接时消息超时 这是详细的客户端日志 来自 sensu client log 的日志 timestamp 2014 07 0

随机推荐

  • ssh框架hibernate 查询方式和查询功能优化

    Hibernate框架的查询方式 1 唯一标识OID的检索方式 session get 对象 class OID 2 对象的导航的方式 3 HQL的检索方式 Hibernate Query Language Hibernate的查询语言 4
  • JavaEE——SmartTomcat的使用教程与常见错误

    SmartTomcat 上一篇博客讲到 使用tomcat创建servlet项目有以下几个步骤 创建maven项目 引入servlet依赖 创建目录 编写代码 打包成war包 拷贝到webapps目录下 运行tomcat 验证程序 可以看到步
  • 设计模式(4)-原型模式(Prototype Pattern)

    所谓原型模式就是从原型实例去复制克隆出新的实例 而绝不是去从类去实例化 就好比打飞机的游戏 我们操作的主角飞机只有一架 可以用单例模式去实现 而敌机好多都是一样的 如果每出一个敌机我们就去new一个敌机的对象 一下来个三十个 就去new三十
  • 【傅里叶级数与傅里叶变换】数学推导——1、基础知识点回顾及[Part1:三角函数的正交性]介绍

    文章内容来自DR CAN关于傅里叶变换的视频 本篇文章提供了一些基础知识点 比如三角函数常用的导数 三角函数换算公式等 文章全部链接 基础知识点 Part1 三角函数系的正交性 Part2 T 2 的周期函数的傅里叶级数展开 Part3 周
  • 42-Golang中的单元测试

    Golang中的单元测试 需求 传统方法 基本介绍 单元测试快速入门总结 综合案例 需求 在工作中 我们会遇到这样的情况 就是去确认一个函数 或者一个模块的结果是否正确 传统方法 在main函数中 调用addUpper函数 看看实际输出的记
  • 内网能ping通telnet 通,不能访问解决

    内网能PING通TELNET通不能访问解决 遇到一个离奇故障 内网 两个主机在同一IP段内 能互相PING通 TELNET对方的WEB服务器端口 通 但用IE访问时不能 显示HTTP400 这明显是客户端系统的问题啊 但如何解决呢 我强烈怀
  • LeetCode 1233. 删除子文件夹(C++)

    思路 1 首先能想到这种判断字符串前缀的题目可以使用前缀树 2 对字符串字典序排序 那么就能满足 一个子文件夹的左边要么是同父文件夹的子文件夹 要么就是他的父文件夹 同时 第一个文件夹一定是父文件夹 那么就可以建立一个父文件夹地址 每次便利
  • vs2019 中文离线安装包下载,类似ISO,不用联网安装vs2019企业版

    vs2019 中文离线安装包下载 类似ISO 不用联网安装vs2019企业版 前言 我们现在微软官方网站下载的安装包一般也就1 2兆 运行这个小安装包的程序时 才真正在网站上下载vs2019 目前的vs2019企业版 专业版 社区版都要20
  • FISCO BCOS 2.9.1 从0部署到简单使用的CRUD接口

    FISCO BCOS 2 9 1 从0部署到简单使用CRUD接口 文章目录 FISCO BCOS 2 9 1 从0部署到简单使用CRUD接口 前言 1 部署fisoc bcos 2 9 1环境 1 1 安装centos依赖 1 2 创建fi
  • Hibernate+spring缓存机制配置

    在applicationContext xml文件中添加以下代码
  • 关于Tp中图片路径的问题

    图片一般放在Public 目录下 在模板文件中引用图片时 src PUBLIC 图片Public 下面的路径 注意在linux下面要区分大小写 windows是不用区分也能识别的 部署服务器上后要严格区分大小写
  • vue之websocket聊天功能实现

    一 首先配置全局websocket 创建webSocket js global js export default ws setWs function newWs this ws newWs main js引入 import webSock
  • iPhone手机使用:微信提示“运行内存不足导致该小程序无法使用“解决方法

    突然发现遇到的一个很诡异的情况 通过分析 解决了 分享一下 如图所示 通过iPhone XR打开微信小程序的时候 微信突然提示 运行内存不足导致该小程序无法使用 然后点击 确定 按钮之后 就关闭了 而且查看手机内存128G的还剩下70G没有
  • org.apache.hive.com.esotericsoftware.kryo.kryoexception: encountered unregistered class id 错误解决办法

    执行hive 任务的时候 有些任务会报下列错误 hive 0 14 版本才会有这个问题 任务重做之后可能又会成功 1 错误信息 hdfs nameservice1 tmp hive dbs 9c29873a 664f 45a4 87f5 a
  • 语音合成方法的主要分类

    语音合成的研究已有多年的历史 现在研究出的语音合成方法的分类 从技术方式讲 可分为波形合成法 参数合成法 和规则合成方法 从合成策略上讲可分为频谱逼近和波形逼近 1 波形合成法 波形合成法一般有两种形式 一种是波形编码合成 它类似于语音编码
  • Redis 6.0 新功能

    1 支持 ACL 1 1 ACL 简介 官网 https redis io topics acl Redis ACL 是访问控制列表 Access Control List 的缩写 该功能允许根据可以执行的命令和可以访问的键来限制某些连接
  • String包含的方法

    public class TestString public static void main String args String s1 new String abc String s2 abc String s3 ABC String
  • 2021-05-28

    什么是散列表 散列表 散列表 Hash table 也叫哈希表 是根据键 Key 而直接访问在内存存储位置的数据结构 也就是说 它通过计算一个关于键值的函数 将所需查询的数据映射到表中一个位置来访问记录 这加快了查找速度 这个映射函数称做散
  • 使用Qt编写模块化插件式应用程序

    动态链接库技术使软件工程师们兽血沸腾 它使得应用系统 程序 可以以二进制模块的形式灵活地组建起来 比起源码级别的模块化 二进制级别的模块划分使得各模块更加独立 各模块可以分别编译和链接 模块的升级不会引起其它模块和主程序的重新编译 这点对于
  • RabbitMQ--基础--10.2--死信队列

    RabbitMQ 基础 10 2 死信队列 1 死信队列 DLX queue 当消息在一个队列中变成死信之后 它能重新被发送到另一个交换机中 这个交换机就是 死信交换机 绑定 死信交换机 DLX Exchange 的队列就称之为死信队列 死