Scenario
- create event
- invite user
- notify users at specific time
- notify user periodically
Service
- User Service. 负责管理用户数据。
- Event Service. 负责管理用户创建的 Events
- Notification Service。负责notify用户某个 event 到了
Storage
created_by (谁创建的)
strategy (一次性的,还是周期的。如果是周期的,那么周期的策略是什么.
每周,还是每周末,还是什么,可以用一个具体的结构化数据表示出来,并serialize成json之类的存起来)
next_notify_time(下一次什么时候提醒,注意这里是下一次什么时候提醒,而不是第一次什么时候提醒)
attendes: many to many 的 users(实际上会存成另外一张表,记录哪个用户参与了哪个event)
freq *(
; either UNTIL or COUNT may appear in a 'recur',
; but UNTIL and COUNT MUST NOT occur in the same 'recur'
( ";" "UNTIL" "=" enddate ) /
( ";" "COUNT" "=" 1*DIGIT ) /
; the rest of these keywords are optional,
; but MUST NOT occur more than once
( ";" "INTERVAL" "=" 1*DIGIT ) /
( ";" "BYDAY" "=" bywdaylist ) /
( ";" "BYMONTHDAY" "=" bymodaylist ) /
( ";" "BYYEARDAY" "=" byyrdaylist ) /
( ";" "BYWEEKNO" "=" bywknolist ) /
( ";" "BYMONTH" "=" bymolist )
)
freq : 事件重复频率,有效值:DAILY(按天),WEEKLY(按周),MONTHLY(按月),YEARLY(按年)
- UNTIL: 重复结束日期 格式:20130102T170000Z(2013-1-2 下午5点结束)
- COUNT: 重复多少次后结束,该字段与UNTIL两者只有出现一次
- INTERVAL: 事件重复的间隔,如按天重复时,INTERVAL=2,则表明每2天重复一次,默认值 为1
- BYDAY: 表示一周的某一天,有效值:MO(周一),TU(周二),WE(周三),TH(周四),FR(周五),SA(周六),SU(周日) , 示例: BYDAY=MO,TH,SU 表示重复日期包括周一,周四,周日. 每个值前面可以用 ”+”, “-” 修饰,表示第几个和倒数第几个日子,如 BYDAY = 2MO 表示第2个星期一发生; BYDAY=MO,-1SU 表示每个星期一和最后一个星期日发生
- BYMONTHDAY: 表示一月的第几天发生,有效值是 [1 ~ 31] 和 [-31 ~ -1] ,如: BYMONTHDAY=2,18 表示一月的第2天,第18天发生; BYMONTHDAY=-1 表示一月的最后一天
- BYYEARDAY: 表示一年的第几天发生,有效值是 [1 ~ 366] 和 [-366 ~ -1], 如 BYYEARDAY=125 表示一年的第125年发生; BYYEARDAY=-1 表示一年的最后一天发生
- BYWEEKNO: 表示一年的第几周发生, 有效值是 [1 ~ 53] 和 [-53 ~ -1], 如 BYWEEKNO=2,23 表示一年的第2周,第23周发生
- BYMONTH: 表示一年中的第几个月发生, 有效值是 [1 ~ 12]
需要注意几点:
- 如果各字段所设置的值是无效的,如 BYMONTHDAY=30 ,则会忽略该值
- 如果某条事件的重复规则表达式缺少一些必要字段,如 YEARLY;BYMONTH=1 ,表示按年重复,每年的1月某日发生,现在缺少”日”字段,则从该事件的”开始日期”中获得
按天重复
目标: 按天重复, 且每3天重复一次
表达式: DAILY;INTERVAL=3
目标: 按天重复, 重复到今年结束
表达式: DAILY;UNTIL=20140101T000000Z
目标: 按天重复, 重复20次
表达式: DAILY;COUNT=20
按周重复
目标 : 每周二,周四,周日重复,每隔2周发生一次
表达式: WEEKLY;INTERVAL=2;BYDAY=TU,TH,SU
按年重复
目标 : 每年的七月,八月两月最后一天
表达式: YEARLY;BYMONTH=7,8;BYMONTHDAY=-1
父亲节
目标 : 每年六月的第三个星期日
表达式: YEARLY;BYMONTH=6;BYDAY=3SU
除夕
目标 : 农历每年的最后一天
表达式: YEARLY;BYMONTH=12;BYMONTHDAY=-1
感恩节
目标 : 每年11月的第四个星期四
表达式: YEARLY;BYMONTH=11;BYDAY=4TH
母亲节
目标 : 每年5月的第二个星期日
表达式: YEARLY;BYMONTH=5;BYDAY=2SU
nextOccurDate: 根据传入的时间计算出以该时间为起始值的下一次事件发生的时间
includes(theDay): 判断指定时间是否是该事件的发生时间点系列之一
主要难Scale 的是,如果是发邮件提醒的那种events,要从服务器端来处理。那么一个进程扫描整个数据库看看到时间的 events有哪些这个是很慢很慢的。所以需要多加机器,通过sharding分开处理。我的想法是按照 created_by 的 user_id 进行 sharding 来让 events存在不同的数据库里。然后弄若干个进程,每个进程负责一个 micro sharding (一个进程负责不了一整个数据库,所以可以按照 micro sharding 来分任务),然后每个进程 Regular 的扫描自己的 micro sharding 中到期的 events,然后创建提醒任务,丢给 MessageQueue。