• 在Magento中用MySQL模拟队列发送电子邮件


    1. 需求
    顾客在网站上购买特定商品并且这些商品的总金额超过特定金额后,使用email给顾客发送一个优惠券;假如某件商品已经降价了,则此商品的金额不计算在目标总金额内;

    2. 需求分析
    ①发送优惠券的规则:i. 购物车中包换特定商品;ii. 这些商品的总金额大于预先设定的特定金额
    ②顾客本次购买的订单中,如果某个商品的实际价格小于原价,则表示此件商品的实际价格是打折后的,则它的价格不会计算在目标总金额内
    ③每次顾客完成支付后,需要对所有的订单商品验证是否符合发送优惠券的规则,此操作可能会比较耗费时间
    ④如果某一个订单验证通过,则生成优惠券并通过email发送,但是发送email这一操作比较耗时

    Magento 里可以很方便的 observer 订单保存( sales_order_save_after )的操作, 在 observer 的方法中,只需要判断这个订单的状态为’processing’即表示为“已支付”,此时可以进行优惠规则验证。
    验证通过,即可通过 email 发送优惠券。但是考虑到验证规则和发送email比较耗时,而 observer 又是实时的,假如直接在 sales_order_save_after 之后进行这两项操作,订单成功页面会出现比较大的延迟。

    3. 解决办法

    在这里,我为 验证优惠规则 和 通过email发送优惠券 这两个操作建立了一个 mysql 表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    CREATE TABLE `coupon_queue` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Queue Id',
      `event_code` varchar(255) DEFAULT '' COMMENT 'Event Code',
      `event_identifier` varchar(255) DEFAULT '' COMMENT 'Event Identifier',
      `event_data` varchar(255) DEFAULT '' COMMENT 'Event Data',
      `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Created At',
      `executed_at` timestamp NULL DEFAULT NULL COMMENT 'Execute At',
      `execute_result` varchar(255) DEFAULT '' COMMENT 'Event Execute Result',
      `is_executed` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Event Execute Status',
      PRIMARY KEY (`id`),
      UNIQUE KEY `UNQ_COUPON_QUEUE_EVENT_IDENTIFIER` (`event_identifier`),
      KEY `IDX_COUPON_QUEUE_EVENT_CODE_IS_EXECUTED` (`event_code`,`is_executed`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Event Queue Table';

    其中,
    event_code 表示某类事件,
    event_identifier 表示某一个事件, 具有唯一性;
    event_data 是执行事件所必需的数据, 它是一个对 array 进行序列化后的得到的字符串;
    execute_result 是事件执行的结果,如果事件执行中有报错,会将报错信息写入这里;
    created_at, executed_at 分别是事件的创建时间和执行时间
    is_executed 表示此事件是否已经执行过了

    通过 observer ‘sales_order_save_after’, 每次当有’processing’的订单的时候, 会在 coupon_queue 中插入一行数据:

    1
    2
    INSERT INTO coupon_queue (event_code, event_identifier, event_data, created_at, is_executed)
     VALUES ( 'add_order_to_queue', '9200000217_processing', 'a:2:{s:8:"order_id";s:10:"9200000217";s:12:"order_status";s:10:"processing";}', '2017-02-23 11:06:40', 0 )

    在 coupon_queue 表中插入一行的代价是很小的,对性能的影响可以忽略不计。然后再通过计划任务来每5分钟执行 coupon_queue 表中未执行的项目:
    首先是读取未执行的 add_order_to_queue 事件:

    1
    SELECT * FROM coupon_queue WHERE event_code = 'add_order_to_queue' AND is_executed = 0;

    coupon_queue 表中 event_data 是已经经过序列化的 array, 对其反序列化后可以得到执行事件时所需要数据。
    在取得 add_order_to_queue 事件的数据后,通过对 event_data 反序列化,可以得到预先为执行此事件准备的数据。事件 add_order_to_queue 的作用是验证order是否符合发放优惠券的条件,如果验证通过,则会在 coupon_queue 表中插入另一个新的事件:

    1
    2
    INSERT INTO coupon_queue (event_code, event_identifier, event_data, created_at, is_executed)
    VALUES ('send_coupon_code_by_email', '9200000217_processing_1_14', 'a:4:{s:8:"order_id";s:10:"9200000217";s:12:"order_status";s:10:"processing";s:13:"promo_rule_id";s:2:"14";s:8:"promo_id";s:1:"1";}', '2017-02-23 11:10:10', 0);

    和上面 add_order_to_queue 事件一样,可以通过如下SQL来获取即将执行的事件的数据:

    1
    SELECT * FROM coupon_queue WHERE event_code = 'send_coupon_code_by_email' AND is_executed = 0;

    这个事件是用来发送email的。和处理 add_order_to_queue 事件一样, 通过反序列 event_data 后可以获得执行发送 email 事件的数据,然后发送email给顾客。

    这样一来,就把订单成功 -> 验证优惠券发放规则 -> 发送email 这一流程转换为两个队列,避免在订单高峰期时,这个非常耗时的流程,对网站业务逻辑的冲击,将实时性不高的业务推迟处理,有效减少了下单成功页面的响应时间。

    如果您觉得阅读本文对您有帮助,欢迎转载本文,但是转载文章之后必须在文章页面明显位置保留此段声明,否则保留追究法律责任的权利。

    作  者:www.jpdou.top

    原文链接:http://www.jpdou.top/use-mysql-to-simulate-queue-to-send-email/

  • 相关阅读:
    java 多线程(synchronized)
    java 多线程(daemon)
    【转】 Nginx深入详解之多进程网络模型
    Linux 网络编程(epoll)
    Linux 网络编程(多路复用)
    Linux 网络编程(UDP)
    Linux 网络编程(TCP)
    STM32F0xx_看门狗(独立+窗口)配置详细过程
    STM32F0xx_FLASH编程(片内)配置详细过程
    STM32F0xx_RTC实时时钟配置详细过程
  • 原文地址:https://www.cnblogs.com/jpdoutop/p/use-mysql-to-simulate-queue-to-send-email.html
Copyright © 2020-2023  润新知