Rich Menu Stat Calculation
Overview
The report that answers "which button on the menu gets tapped the most" is produced by
aggregating tracking_log records against each menu's button layout, stored in the
rich_menu_action table.
The job is split into two levels so it scales:
calculate_rich_menu_stat— the fan-out job, which determines which rich menus need recalculating and breaks the work into per-menu jobscalculate_rich_menu_stat_item— the job that does the actual calculation for a single rich menu
This split keeps a menu with a huge log volume from blocking the others, and allows retries at the individual menu level.
Business Flow
Cron trigger (profile cron-scheduler)
- On the hour (
0 * * * *),RichMenuStatScannerServicescans Redis for keys prefixed withRICH_MENU_STAT_DIRTY:followed by a rich menu id. These are set by the tracking path whenever a user taps a menu button. - It extracts the id and publishes one job per rich menu onto
calculate_rich_menu_stat_item. - If no dirty keys exist, the cycle is skipped entirely.
calculate_rich_menu_stat (profile main)
processCalculateRichMenuStat finds every rich menu still marked active and publishes a
calculate_rich_menu_stat_item job for each one — a full-sweep fan-out.
calculate_rich_menu_stat_item (profile main)
- Load the rich menu joined with all its
rich_menu_actionrows, capturingtype,label,link(the original destination before the tracking redirect wraps it), andindex. transformRichMenureshapes this into a single menu object with its list of actions.- Pull that menu's
tracking_logrows and summarise them withsummarizeRichMenuStats:totalClick— total taps per buttonuniqueClick— count of distinctline_uidvalues
- The result is a
statDataarray of entries carryingtype,label,link,totalClick, anduniqueClick. - Write the result back to
rich_menuand torich_menu_archivefor member/guest menus that keep archived snapshots.
Key Files & Functions
internal/richmenu/consumer.go—OnProcessCalculateRichMenuStat,OnProcessCalculateRichMenuStatItem, theRichMenuStatPayloadstructinternal/richmenu/service_stats.goService.calculateRichMenuStats(ctx, richMenuInfo)transformRichMenu(),summarizeRichMenuStats()- the
statDataandstatItemstructs (fieldsType,Label,Link,TotalClick,UniqueClick)
internal/richmenu/service_methods.go—processCalculateRichMenuStat(),processCalculateRichMenuStatItem()internal/cronscheduler/rich_menu_stat_scanner.go—RichMenuStatScannerService.Run(ctx)and the constantrichMenuDirtyKeyPrefix = "RICH_MENU_STAT_DIRTY:"- Queues:
calculate_rich_menu_statandcalculate_rich_menu_stat_item(profilemain), published by the cron running under thecron-schedulerprofile
Connections to Other Services
- Tables:
tracking_log(raw data),rich_menuplusrich_menu_action(button layout), andrich_menu_archive(statistic snapshots for menus that have been replaced) - Redis: keys prefixed
RICH_MENU_STAT_DIRTY:mark which menus have new data awaiting calculation - Consumers of the output: cms-api-go and cms-web on the rich menu report screens
- This job makes no LINE API calls