【问题标题】:Sending notification emails based on each db record timestamp根据每个数据库记录时间戳发送通知电子邮件
【发布时间】:2013-06-08 02:11:50
【问题描述】:

我有一个“事件”数据库(会议、生日聚会等)记录,每个事件都有一个endTime 字段。活动结束后,我想为每个过去的活动发送 2-3 封电子邮件。

现在,我运行一个每小时 cron 作业来查找过去一小时内结束的所有事件,所以它看起来像:

  • 下午 2:01:查找下午 1-2 点之间结束的所有事件,发送电子邮件
  • 下午 3:01:查找下午 2-3 点之间结束的所有活动,发送电子邮件
  • 下午 4:01:查找下午 3-4 点之间结束的所有活动,发送电子邮件
  • 下午 5:01:...

但是,假设下午 3:01 的作业由于某种原因失败(Heroku 使我的 rest api 崩溃,电子邮件服务提供商出现故障等),下午 2-3 点之间结束的事件将不会收到电子邮件。

目前,如果电子邮件发送成功,我的数据库记录不会标记为notified。我应该这样做,以便我可以将 cron 脚本更改为“查找当前时间之前的所有记录notified=false”(它会捕获所有以前未发送的记录)?然后,您会为您成功发送的每种类型的电子邮件设置一个标志吗?

或者有没有更聪明的方法可以避免设置标志?

(想出这个问题的标题和标签真是太棒了——欢迎提出建议/编辑!)

【问题讨论】:

    标签: sql database email database-design cron


    【解决方案1】:

    notified 标志的问题在于,它需要一个索引才能使 WHERE notified = FALSE1 高效,但 TRUE 值仍保留在索引中,尽管再也不会在查询中使用。

    随着时间的推移,您将在索引中有一个小的 FALSE 部分(这很有用)和一个巨大的 TRUE 部分(这只是浪费空间)。如果您的 DBMS 支持它,请使用某种 partial index 从索引中删除 TRUE:

    或者,创建一个包含一行和一个字段的额外表:LAST_SENT2,并在成功发送大量通知时更新该字段。这当然可以避免乱序发送通知,并且您需要谨慎处理部分失败,因为您不能只是跳过不成功的通知。


    1 将 FALSE 替换为适合您的数据库的任何内容。

    2如果您的表使用自动递增整数作为主键,请考虑将其用于 LAST_SENT 而不是时间戳,以避免出现时间戳可能不唯一的极端情况。

    【讨论】:

    • 我仍然不确定是否为每种电子邮件类型添加一个字段(和索引)是否可行?但是,如果我确实这样做,这些会有所帮助。
    • @thatmarvin 另一种选择是简单地有两个表:一个用于已发送的通知,另一个用于未发送的通知。发送通知时,只需将其从一个表移动到另一个表即可。显然,如果您需要一个跨越两个表的键并且可能重复 FK,这可能会出现问题,但如果您的 DBMS 支持,可以通过对表进行分区(因此它在逻辑上仍然是一个表)来缓解这种情况。
    • 我的桌子还很小,所以我想要目前最简单的解决方案。我现在实际上正在使用 MongoDB,但计划很快切换到 postgresql(因此有误导性的标签)。我正在寻找的答案是“是的,你肯定需要标志来做到这一点”,或者“不,还有其他事情你可以在没有标志的情况下做”。听起来你在说“是”!
    • 您关于索引的观点帮助我从不同的角度看待问题,所以如果没有其他问题,我会在接下来的几天内接受这个答案。谢谢 Branko!
    【解决方案2】:
    CREATE TABLE events_tbl
    (
        e_id    NUMBER
    ,   e_date  DATE
    ,   e_info  VARCHAR2(4000)
    );
    
    INSERT INTO events_tbl VALUES (43, '2000-01-01 01:10:00', 'event1');
    INSERT INTO events_tbl VALUES (44, '2000-01-01 01:15:00', 'event2');
    INSERT INTO events_tbl VALUES (45, '2000-01-01 01:20:00', 'event3');
    INSERT INTO events_tbl VALUES (46, '2000-01-01 01:25:00', 'event4');
    
    INSERT INTO events_tbl VALUES (47, '2000-01-01 02:10:00', 'event5');
    INSERT INTO events_tbl VALUES (48, '2000-01-01 02:15:00', 'event6');
    INSERT INTO events_tbl VALUES (49, '2000-01-01 02:20:00', 'event7');
    INSERT INTO events_tbl VALUES (50, '2000-01-01 02:25:00', 'event8');
    
    /* table that holds information about sent events */
    CREATE TABLE events_sent_tbl
    (
        s_e_id NUMBER
    ,   s_date DATE
    );
    
    INSERT INTO events_sent_tbl VALUES (43, '2000-01-01 02:01:00');
    INSERT INTO events_sent_tbl VALUES (44, '2000-01-01 02:02:00');
    
    SELECT  *
    FROM    events_tbl
    WHERE   TO_NUMBER(TO_CHAR(e_date, 'MMDDHH24MiSS')) BETWEEN 0101010000 AND 0101015959
    AND     NOT EXISTS
            (
                SELECT  1
                FROM    events_sent_tbl
                WHERE   e_id = s_e_id
            )
    ;
    /*
    45  2000-01-01 01:20:00 event3
    46  2000-01-01 01:25:00 event4
    */
    

    合作:

    • 要发送的事件
    • 发送事件

    ...在集合中。将 events_tbl 和 events_sent_tbl 读入集合。发送数据并更新集合中的信息。将其与 FORALL 一起转储到 events_sent_tbl 表中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-30
      • 2021-07-26
      • 1970-01-01
      • 2019-01-28
      • 2018-08-23
      • 1970-01-01
      相关资源
      最近更新 更多