p.fontbold{ font-weight: bold; } p.codeboxbefore{ margin-bottom:-70px; } @media screen and (max-width: 575px) { p.codeboxbefore{ margin-bottom:-13.4vw; } } ãã®èšäºã¯ Merpay & Mercoin Tech Openness Month 2026 ã® 13 æ¥ç®ã®èšäºã§ãã ããã«ã¡ã¯ãGrowth Platform Team ã§ã¡ã«ãã€ã®ãã€ã³ãéå
ãã£ã³ããŒã³åºç€ã§ãã Santa ãµãŒãã¹ã®éçºãæ
åœããŠãã @hasegway ã§ãã ãªããã¿ã€ãã«ã«ç»å ŽãããOtoku Revolutionããšã¯ãã³ãŒã決æžãäžå®åæ°äœ¿ããã³ã«å¿
ãå€åŒãäœéšãå±ãæ°äŒç»ã®ãã£ã³ããŒã³ (æ¬èšäºã§ã¯ãã³ãŒã決æžã®åæ°é£åãã£ã³ããŒã³ããšåŒã³ãŸã) ã®ç€Ÿå
åŒç§°ã§ãã詳ããã¯æ¬é£èŒ 17 æ¥ç®ã® @yutaro ã®èšäºã楜ãã¿ã«ããŠããŠãã ãããæ¬èšäºã§ã¯ãé·ãéçšããŠãã Santa ãµãŒãã¹ãã«ãŒã«ããŒã¹ã®æ±çšåºç€ (以éãRulebase åºç€ããšåŒã³ãŸã) ãšããŠæžãçŽãããªãã¡ã¯ã¿ãªã³ã°ã®è©±ãšãæ°åºç€ã®æåã®ãã£ã³ããŒã³ãšããŠãã³ãŒã決æžã®åæ°é£åãã£ã³ããŒã³ããç«ã¡äžãã話ãåãäžããŸããé ã远ã£ãŠã話ãããåã«ããŸã Santa ãšããåºå¹¹ãµãŒãã¹ãã©ã®ãããªæŽå²ãçµãŠãã©ããªè² åµãæ±ããã«è³ã£ããã«ã€ããŠã話ããããŠãã ããã Santa ã®æŽå² Santa ãšããååã¯ãåæã« ã䜿ã£ãç¿æ¥ã«ãããåŠçã§ãã€ã³ããä»äžããã ãµãŒãã¹ã ã£ããšããããæ¥ãŠããŸããå€ã®ãã¡ã«æºãŸã£ãã€ãã³ããç¿æãŸãšããŠé
ã£ãŠåããã·ã³ãã«ãªä»çµã¿ã§ãã (åæã®ä»çµã¿ã«ã€ããŠã¯ ã¡ã«ãã€ã®ãã£ã³ããŒã³ãæ¯ãããµã³ã¿ã®ç§å¯ ã詳ããã§ã)ã ããããäœå¹ŽãçµãŠãä»ã§ã¯ 1 æ¥æ°çŸäžã€ãã³ããåŠçããã¡ã«ã«ãª / ã¡ã«ãã€ã®ããŸããŸãªå©çšã·ãŒã³ã§ãã€ã³ãä»äžãè¡ãåºå¹¹ãµãŒãã¹ãžãšæé·ããŸããããã®æé·ã®éçšã§äžè²«ããŠããã®ã¯ã ããã£ã³ããŒã³ã®çš®å¥ããšã«å°çšã®ã€ãã³ããã€ãã©ã€ã³ãå®è£
ããã ã¹ã¿ã€ã«ã§æ©èœãç©ã¿éããŠããããšã§ããããããç¬èªã®ããŒãã«ãç¬èªã®ã€ãã³ããã³ãã©ãç¬èªã® Cap (äžé) ããžãã¯ãç¬èªã®ãã€ã³ãä»äžãããŒãæã£ãŠããŸããã 2021 幎ã®ãã£ã«ã¿ãªã³ã°æ©èœ ã¯ãè€æ°ã®æ¡ä»¶ã AND/OR ã§çµã¿åãããã çºæ³ã Santa ã«æã¡èŸŒãã ãæ±çšåã®æåã®äžæ©ã§ããã 2022 幎ã®ã¡ã«ã«ãŒãåžžæéå
ã¯ããã®äžã«ãã¡ã«ã«ãŒãã¹ããŒãžå¥ã®éå
çããè€æ°æã«ãŸããã Provision (åŒåœé) 管çã ãšãã£ã粟緻ãªããžãã¯ãä¹ããå€§èŠæš¡ãªãã€ãã©ã€ã³ã§ãçŸåšã§ã Santa æå€§ã®ãã€ãã©ã€ã³ã§ããããã§ãããã£ã³ããŒã³æ¬äœã®ã³ãŒã㯠CampaignType ããšã«å¥ç©ã®ãŸãŸã§ããã ãã®æ§é ã¯åœåã®èŠä»¶ã«ãããŠã¯åççã§ãããããããã£ã³ããŒã³èŠä»¶ã®è€éåãšãšãã«ãã³ãŒãã®åå©çšæ§ãäœãèšèšã«ããéçºé床ã®äœäžããã°ã®ãã£ã³ããŒã³å¥å¯Ÿå¿ã«ããéçšè² è·ã®å¢å€§ãšãã£ã課é¡ãç©ã¿éãªã£ãŠãããŸããã2025幎å€ã®æç¹ã§ã¯ãSanta ãšã³ãžãã¢ããŒã å
ã§ããã課é¡ãžã®å
±éçè§£ãã§ããŠãããæ¬¡äžä»£ãã£ã³ããŒã³æ§é ã®ã©ãèšèšãŸã§é²ãã§ããŸããããã ãåœæã¯ã¹ã±ãžã¥ãŒã«äžã®å¶çŽã§æ¬æ ŒçæãèŠéãã2025幎10æã«ããŒã³ãããã¡ã«ã«ãªã¢ãã€ã«åãç¹å
žãã£ã³ããŒã³ã¯æ¢åã·ã¹ãã ãæ¡åŒµãã圢ã§å®è£
ããŸããã ãã®åŸãPoCãé²ãã2025幎12æã«ããŒã åãã«ææãçºè¡šã2026幎æ¥ã«ãããŠãæ±çšãã£ã³ããŒã³ããŒãã«ã«ã«ãŒã«è©äŸ¡ãšã¢ã¯ã·ã§ã³å®è¡ã¢ãžã¥ãŒã«ãçµã¿åããã Rulebase åºç€ãæ°èŠã«æ§ç¯ããŸãããçŸæç¹ã§ã¯ãã³ãŒã決æžã®åæ°é£åãã£ã³ããŒã³ãã1件皌åãããŠããæ®µéã§ãæ¢åã®ãã£ã³ããŒã³çŸ€ã¯åŒãç¶ãåŸæ¥ã®å°çšãã€ãã©ã€ã³ã§åããŠããŸãããããæ¢åãã£ã³ããŒã³ã®æ®µéçãªç§»è¡ã¯ãããããå
ã®ãã§ãŒãºã§ãã å°çšãã€ãã©ã€ã³ãæ±ããè² åµ Rulebase åºç€ãäœãåã® Santa ã¯ããã£ã³ããŒã³ã®çš®å¥(CampaignType) ããšã«ãå°çšãã€ãã©ã€ã³ããå®è£
ããããšããã¹ã¿ã€ã«ã§æé·ããŠããŸããã代衚çãªãã£ã³ããŒã³çš®å¥ãšãåçš®å¥ã®ä»£è¡šçãªãã£ã³ããŒã³äŒç»ã¯æ¬¡ã®ãšããã§ãã ãã£ã³ããŒã³çš®å¥ äž»ãªãã£ã³ããŒã³äŒç» 賌å
¥æéå
ãè²·ã£ãŠãåŸ!dãã€ã³ãããªã© ã¡ã«ãã€ã®å®é¡æãã®éå
ãã¯ãããŠã®å®é¡æããã£ã³ããŒã³ããªã© ã¡ã«ãã€ã¹ããŒããããŒã®éå
ãååå©çšããã«ã ããã¯ãã£ã³ããŒã³ããªã© ã¡ã«ã«ãŒãéå
ãã¡ã«ã«ãŒãåžžæéå
ããªã© ãããã®çš®å¥ã¯ããããããå°çšã®ããŒãã«çŸ€ã決æžãè¿æžãåãåã Pub/Sub ã®å
¥ãå£ãããžãã¹ããžãã¯ãæ
ã Interactorããã€ã³ãä»äžå±¥æŽããŒãã«ãžã®æžã蟌ã¿ãã¹ãä»äžäžéã®èšç®ããžãã¯ãæ±ããŠããŸãããŸããäŒç»ããšã®çްããèŠä»¶ã®å®çŸã®ãããåºæ¬ã®ãã€ãã©ã€ã³ã®äžã«ããŸããŸãªåå²åŠçãå ããããŠããŸããæ°ãã«ãã£ã³ããŒã³äŒç»ã 1 æ¬ç«ãŠããã³ã«ããããã®ããŸããŸãªã¬ã€ã€ãŒãåå¥ã«èª¿æ»ã»å€æŽããªããã°ãªããªãããšããã®ã Santa ã®æšæºäœæ¥ã§ããã ãããŠãé·å¹Žéçšãããªãã§ãã®æ§é ãããã€ãã®è² åµãçãã§ããŸããã 环ç©ããéçšè² åµ ãŸããå°çšãã€ãã©ã€ã³ãå®è£
ããã¹ã¿ã€ã«ã§ã¯ãæ°ããªãã£ã³ããŒã³èŠä»¶ã®ããã®è¿œå éçºã暪å±éããŠåå©çšãã¥ããåé¡ããããŸããããŸããåœåã«æ³å®ããŠãããã£ã³ããŒã³èŠä»¶ã§ã¯èããããªãã£ãæ°ããªèŠä»¶ã¯ãåå¥å®è£
ã§å¯Ÿå¿ããããåŸãªãããšããããŸããããããã¯åŸã
ã«éçºé床ã®äœäžããªã°ã¬ãã·ã§ã³ãã¹ãã®è€éåãæããŠãããŸãããç¹ã« MercardCampaignType ã§ã¯ãã®åé¡ãé¡èã§ããªãã¡ã¯ã¿ãªã³ã°ã«èžã¿åãçŽæ¥çãªåŒãéã«ãªããŸããã MercardCampaignType ãããªãã§ã眮ãå ŽãåããŠãã£ã 2022 幎ã«ããŒã³ããã MercardCampaign ãã€ãã©ã€ã³ã¯ãåœåãå©çšã¹ããŒãžå¥ã®éå
çããšãæž
ç®èµ·ç¹ã®ãªã¢ã«ã¿ã€ã ã®ãã€ã³ãä»äžããçŽ çŽã«æ±ãããšãæ³å®ãããã·ã³ãã«ãªåžžæéå
ãã£ã³ããŒã³åãã®èšèšã§ããã ãã®åŸãã¡ã«ã«ãŒããŸããã®ãã£ã³ããŒã³èŠä»¶ã¯æ¥éã«åºãã£ãŠãããŸãã环èšè³Œå
¥é¡é£åãã£ã³ããŒã³ãã¡ã«ã«ãª NFT 決æžãžã®å¯Ÿå¿ãã¡ã«ã«ãŒã ãŽãŒã«ããã¡ã«ã«ãªã¢ãã€ã«å¥çŽè
åãã®ç¹å
žãªã©ãã©ãããã¡ã«ã«ãŒãä¿æè
ã»å©çšè
ããšããå
±éã®æèã¯ãããã®ã®ãèšèšåœæã®æ³å®ã«ã¯ãªãã£ãèŠä»¶ã°ããã§ããããã§ã眮ãå ŽãšããŠã¯ MercardCampaignType ãæãé©åã ã£ãããããããã®æ°èŠä»¶ã¯é 次 MercardCampaignType ã®äžã«å®è£
ãããŠãããŸããæ¬æ¥ã·ã³ãã«ã«èšèšãããŠããå
¥ãç©ã«æ³å®å€ã®æ©èœã次ã
ãšè¿œå ãããéå
çç®åºãäŒèšã³ãŒãæå®ãªã©ã®ä»çµã¿ãæ¬æ¥ã®çšéãè¶
ããŠæµçšãããããã«ãªã£ãŠãããŸããã ããã§ã¯ãç¹ã«æªã¿ãç®ã«èŠãã圢ã§è¡šé¢åãã3 ã€ã®äºäŸ â 环èšè³Œå
¥å (2024 幎 9 æ)ãã¡ã«ã«ãª NFT äŒèšã³ãŒãå·®ãæ¿ãå¯Ÿå¿ (2025 幎 12 æ)ãã¡ã«ã«ãªã¢ãã€ã«åãç¹å
žãã£ã³ããŒã³ (2025 幎 10 æ) â ãé ã«èŠãŠãããŸãã 环èšè³Œå
¥å ãš ã¡ã«ã«ãª NFT äŒèšã³ãŒãå·®ãæ¿ã 环èšè³Œå
¥é¡é£åãã£ã³ããŒã³ã§ã¯ã賌å
¥éé¡ãè€æ°ã®ãããå€ãé ã«è¶
ãããã³ã«æ®µéçã«ãã€ã³ããä»äžãããŸã (äŸ: 环èšè³Œå
¥é¡ã«å¿ããŠæå€§ P1,500 ãããã)ããã®ãã£ã³ããŒã³ã MercardCampaignType ã«æå
¥ãããæ¬æ¥ã®éå
çã¹ããŒãã«ã賌å
¥çޝç©ãã©ãã«ãŒãåã®æåãä¹ããŸãããã¡ã«ã«ãª NFT äŒèšã³ãŒãå·®ãæ¿ã察å¿ã§ã¯ããã£ã³ããŒã³ã®åçš®æ¡ä»¶ã¯ä»ãšå
±éã«ãã€ã€NFTååŒã®ã¿äŒèšã³ãŒããå·®ãæ¿ããããšããèŠä»¶ã®ãããã³ãŒãå
ã«åå²åŠçã远å ããããã£ã³ããŒã³èšå®å€ãè€éåããŸãããã©ã¡ããã¡ã«ã«ãŒãä¿æè
åãã®æœçã§ã¯ãããã®ã®ãåœåæ³å®ã®è²¬åç¯å²ãè¶
ããèŠä»¶ã§ãã ãããŠ3 äŸç®ã®ããã£ãšãæªã¿ã倧ããåºãã±ãŒã¹ããã¡ã«ã«ãªã¢ãã€ã«åãç¹å
žãã£ã³ããŒã³ã§ãã ã¡ã«ã«ãªã¢ãã€ã«åãç¹å
žãã£ã³ããŒã³ (2025 幎 10 æ) ã¡ã«ã«ãªã¢ãã€ã«åãç¹å
žãã£ã³ããŒã³ã®èŠä»¶ã¯ã 3 çš®é¡ã®ã¡ã«ã«ãŒãã¹ããŒã¿ã¹ (ä¿æç¡ã / éåžžç / ãŽãŒã«ã) à 4 çš®é¡ã®ã¢ãã€ã«ããŒã¿ãã©ã³ (4GB / 10GB / 20GB / 40GB) = 12 ã®ç¬ç«ãããã£ã³ããŒã³ãã¿ãŒã³ãæ¯æå¿
èŠããšãããã®ã§ããã å®è£
äžã¯ãæ¬æ¥ã¡ã«ã«ãŒãã¹ããŒãžå¥ã®éå
ã¬ãŒããä¿æããDBãã£ãŒã«ãããããŒã¿ãã©ã³å¥ã®ã¬ãŒããã®å
¥ãç©ãšããŠæµçšãããŸããã3 ã¹ããŒã¿ã¹ Ã4 ããŒã¿ãã©ã³ã® 12 çµã¿åããããã¡ã«ã«ãŒãçšããŒãã«ã®è¡ãšããŠæ¯æçæããéçšã§ãã ãŸããã客ããŸã®ã¡ã«ã«ãŒãã¹ããŒã¿ã¹ãã¢ãã€ã«ããŒã¿ãã©ã³ã¯æ¥ã
å€ããããããå€åã«åãããŠéå
ã¬ãŒããæã
ã®äžéãèšç®ãçŽãå¿
èŠããããŸãããããŠãåãã客ããŸãåæå
ã§å¥ã®çµã¿åããåããã£ã³ããŒã³ã«ãäºéã«ãããããŠéè€ä»äžãèµ·ããããããšãããªã¹ã¯ãæ®ããŸããåŸè
ã®éè€ä»äžãé²ãããã«ãã³ãŒãåŽã«ã¯ãããªé°å²æ°ã®ããŒãã³ãŒãããããå
¥ããŸãã (ç°¡ç¥åããã€ã¡ãŒãž)ã // ãã€ã³ãéè€ä»äžé²æ¢ã®ããããã£ã³ããŒã³IDãã³ãŒãã«åã蟌㿠TemporaryCampaignIDMapping = map[string]string{ "202510": "campaign-id-1", "202511": "campaign-id-2", // æ¯æè¿œå ãå¿
èŠ... ãããŠåæã«ãããŒã¿ãã©ã³å¥ã¹ããŒãžãå€å®ãã if æãæ£ãã°ããŸããã ããããŠãæ¯æ 12 ãã¿ãŒã³åã®ããŒã¿è¿œå éçšãå¿
èŠãªãTemporaryãããŒãã³ãŒãããããæ¬çªã«å±
ç¶ãïŒTemporaryãšã¯ã»ã»ïŒãã¢ãã€ã«å°çšã¹ããŒãžãåå²ããã if æããã€ã³ãèšç®ã»ãã£ã«ã¿è©äŸ¡ã»API ã¬ã¹ãã³ã¹ã«æ£åšããå°æ¥ããŒã¿ãã©ã³ã1ã€å¢ãããã³ã«ã³ãŒã倿Žãšãããã€ãå¿
èŠã«ãªããMercardCampaignType å
šäœã®ãªã°ã¬ãã·ã§ã³ãã¹ããå·»ã蟌ãããšããæ§é ãåºæ¥äžãã£ãŠãããŸããåœå㯠ãã¢ãã€ã«ãã£ã³ããŒã³ãã¢ãŒããã¯ãã£å·æ°ã®ãã£ããã«ããŠææ¬å¯Ÿå¿ããã èšç»ããããŸããããããŒã³ãææ¥ãšã®äž¡ç«ãé£ãããæçµçã«æ¢åãã€ãã©ã€ã³ãæ¡åŒµãã倿ãåããŸãããåœæã®å¶çŽäžã§ã¯åççãªéžæã§ãããæ ¹æ¬çãªæ§é 課é¡ã¯æã¡è¶ããéçšè² è·ã¯å¢ããŠããŸãã 3 äºäŸãšãããžãã¹æèã§ã¯çãéã£ãŠããäžæ¹ããã¡ã«ã«ãŒãéå
ã®å
¥ãç©ãããã¡ã«ã«ãŒãåšèŸºãã£ã³ããŒã³å
šè¬ã®å
¥ãç©ããšããŠäœ¿ãããMercardCampaignType ã®ã¹ããŒããšè²¬åç¯å²ãæŒãåºããããŠããã®ãåœæã®ç¶æ
ã§ããã®ã²ãã¿ã¯ç¡èŠã§ããªã倧ããã«ãªã£ãŠããŸããã Rulebase åºç€ã®èšèš ãã®ãªãã¡ã¯ã¿ãªã³ã°ãã®ãã®ã¯åããæ€èšããŠãããã®ã®ãããŒã³ã責任ãšã®äž¡ç«ãé£ãããæ¬æ Œçæã¯å幎å¯ãããŠããŸãããã®éãå
éšã§ PoC ã¯é²ããæ¬å®è£
ã§åºããæ¹éã¯ããã£ã³ããŒã³ã®æåããå°çšã³ãŒãããèšå®ããŒã¿ãžããšããã·ã³ãã«ãªãã®ã§ãã ããå
·äœçã«ã¯ã ãã©ã®ãããªãã£ããã§åããã (TriggerType)ã ãã©ã®ãããªæ¡ä»¶ã§ãããããããã (RuleCondition ãšããã®è©äŸ¡ãæ
ã RuleEvaluator)ã ãäœããããã (ActionExecutor) ãšãã3 ã€ã®è»žããã§ããã ã atomic 㪠(åå©çšå¯èœãªãµã€ãºã®) éšåãšããŠå®çŸ©ãããã®çµã¿åããã§å€æ§ãªãã£ã³ããŒã³èŠä»¶ã«å¯Ÿå¿ããããšããã®ãåºæ¬çãªçºæ³ã§ããåŸæ¥ã®ããã«ãã¡ã«ã«ãŒããã£ã³ããŒã³å°çšã®ããžãã¯ãæžãäžãããã®ã§ã¯ãªããTrigger / Condition / Action ãå°ããªéšåãšããŠçšæãããã£ã³ããŒã³å®çŸ©ã¯ãã®çµã¿åãããšããŠæžãããšããçºæ³ã§ããå°çšãã€ãã©ã€ã³æä»£ãšã®æ ¹æ¬çãªéãã¯ããã«ãããŸããäžåºŠå®è£
ãã Condition ã Action ãå¥ã® CampaignType ããèšå®å€ã ãã§åŒã³åºããããåçãªæ¡ä»¶åå²ãç¹°ãè¿ãæ¡ä»¶ã1 ã€ã®ãã£ã³ããŒã³å®çŸ©ã®äžã§è¡šçŸã§ãããããèœåããããããçãŸããŸãã å
šäœå ããŒã å
çºè¡šã§ããæ¬¡ã®å¯Ÿæ¯ã䜿ã£ãŠèª¬æããŸããã As-Is (ã¡ã«ã«ãŒãå°çšãã³ãã©ã®å
éšã« if ãç©ãŸããŠãã) func (h *MercardCampaignHandler) Execute(event Event) { if user.Stage == StageA { if user.Status == "Active" { if !h.HasReward(user.ID, event.ID) { points = amount * 0.03 h.RewriteRewardHistory(user.ID, event.ID) } } } else if user.Stage == StageB { if user.Status == "Gold" { points = amount * 0.10 if h.HasReward(user.ID, event.ID) { h.RewriteReward(user.ID, event.ID, points) } } } } To-Be (ãã£ã³ããŒã³å®çŸ©ã¯ JSON ããŒã¿ãè©äŸ¡ãšã³ãžã³ã¯æ±çš) { "rule_id": "mobile-std-4gb", "conditions": [ {"type": "user_attribute", "params": {"stage": "Standard", "plan": "4GB"}}, {"type": "period", "params": {"start": "2025-10-01", "end": "2025-10-31"}}, {"type": "payment_attribute", "params": {"transaction_type": "code_payment"}} ], "action": { "type": "ADD_POINTS", "params": {"rate": 0.05, "currency_points": 60, "monthly_cap": 200} } } ãã® JSON ã Spanner ã«æ°žç¶åããã¹ããŒããæ¬¡ã®3 ããŒãã«ã§ããCampaigns é
äžã« CampaignRulesããã®é
äžã« RuleConditions ã INTERLEAVE IN PARENT ã§äžŠã¹ãæ§é ã«ãªã£ãŠããŸãã -- 倧æ ã®å®£èš: æéã»CampaignTypeã»ãã£ã³ããŒã³åºæèšå® (JSON) Campaigns( CampaignID, CampaignType, StartAt, EndAt, Metadata, ... ) -- 1 ãã£ã³ããŒã³å
ã®è€æ°ã«ãŒã«: äœãããªã¬ã«ãã©ãéèšããã©ããªã¢ã¯ã·ã§ã³ãåãã CampaignRules( CampaignID, RuleID, TriggerType, CalculationType, ActionType, ActionParams (JSON), Priority, Enabled ) INTERLEAVE IN PARENT Campaigns -- 1 ã«ãŒã«å
ã®è€æ°æ¡ä»¶: AND/OR ã°ã«ãŒãã§åæ RuleConditions( CampaignID, RuleID, ConditionID, ConditionType, ConditionParams (JSON), ConditionGroup ) INTERLEAVE IN PARENT CampaignRules ããã«å¯Ÿå¿ããè©äŸ¡ãšã³ãžã³ (Rule Evaluation Engine) ãæ°èšãã以äžã®ãããª4 å±€æ§é ã® EvaluationData ãå
¥åãšããŠèµ°ãããŸãã Layer å
容 Event Data åä¿¡ãã Pub/Sub ã€ãã³ã Rule & Campaign DB ããèªãã CampaignRule + RuleConditions User Data ã客ããŸã®å±æ§ (ã«ãŒãçš®é¡ãå©çšå±¥æŽãªã©) Providers å€éšãµãŒãã¹ãžã® DI ãã³ãã« ã€ãã³ããå±ããŠããä»äžãŸã§ã®æµãã¯æ¬¡ã®ãšããã§ãã Condition/Rule ãš Action ã¯ãæ°ããçš®å¥ãå¿
èŠã«ãªã£ããšãã«å¯Ÿå¿ããå®è£
ã远å ããŠããããšã§ã以éã®ãããããã£ã³ããŒã³å®çŸ©ããåå©çšã§ããä»çµã¿ã«ãªã£ãŠããŸããæ°èŠãã£ã³ããŒã³ã®ç«ã¡äžãèªäœã¯ããã§ã«ã«ã¿ãã°ã«æã£ãŠãããã®ã®çµã¿åããã§å®çŸã§ãããã®ã§ããã°ãã³ãŒã倿Žã䌎ããã« SQL ã® INSERT ã§åæ ã§ããŸãã 3 ã€ã®è»žã®äžèº« ããããã¯ãåè¿°ãã3 ã€ã®è»žã Rulebase åºç€ã®äžã§ããããã©ãèšèšãããŠããããé ã«èŠãŠãããŸãã TriggerType â ã©ã®ãããªãã£ããã§åãã CampaignRules ããŒãã«ã® TriggerType åããåã«ãŒã«ããã©ã®ã€ãã³ãã«åå¿ãããã ã衚ããŸãã TriggerType ã¯å€éšã€ãã³ããš1察1ã«ãªãããå®çŸ©ããŠãããPub/Sub ããå±ããã¡ãã»ãŒãžãå
éšãã¡ã€ã³ã®ã¢ãã«ã«æ£èŠåããããã§ãåèŽãã TriggerType ãæã€ã«ãŒã«çŸ€ã CampaignRules ããåŒãåœãŠãæ¡ä»¶ãããã³ã°ãæ
ã2 段ç®ã®ãã³ãã©å±€ã«åŒãæž¡ããšãããŸã§ãããã®è»žã®è²¬ä»»ç¯å²ã§ããæ¡ä»¶è©äŸ¡ãå¯äœçšã¯ããã§ã¯æ±ãããåŸæ®µã«åãåºããŠããŸãã RuleCondition ãš RuleEvaluator â ã©ã®ãããªæ¡ä»¶ã§ããããããã CampaignRules ã«çŽã¥ã RuleConditions ããŒãã«ã«ã¯ãè©äŸ¡ãããæ¡ä»¶ã1è¡1 ä»¶ 䞊ãã§ããŸããåã¬ã³ãŒãã¯æ¬¡ã®3 ã€ã§æ§æãããŸãã ConditionType ã¯ããã®æ¡ä»¶ãã©ããªçš®é¡ã®å€å®ããããã瀺ãåé¡ã§ãåŸæ®µã§ã©ã® ConditionEvaluator ã«ãã£ã¹ãããããããæ±ºããŸãã ConditionParams ã¯ããã® ConditionType ã«æž¡ãå
·äœçãªãã©ã¡ãŒã¿ã§ãçš®å¥ããšã«å¿
èŠãªåŒæ°ãéããããåºå®ã¹ããŒãã§ã¯ãªã JSON ã§æè»ã«ä¿æããŠããŸãã ConditionGroup ã¯ãè€æ°ã®æ¡ä»¶ã AND ãš OR ã§çµã¿åãããããã®ã°ã«ãŒãã³ã°ã©ãã«ã§ãããã䜿ãããšã§ A AND (B OR C) ã®ãããªè€åçãªè«çåŒãããã©ãããªè¡ããŒã¿ã§è¡šçŸã§ããããã«ããŠããŸãã ããšãã°ãããæéå
ã§ãã客ããŸå±æ§ B ã C ã®ããããã«ããããããæç«ã ãšãã A AND (B OR C) ã®æ¡ä»¶ã¯ãRuleConditions ããŒãã«ã«æ¬¡ã®ããã« 3 è¡ã§äžŠã³ãŸãã ConditionID ConditionType ConditionGroup ã°ã«ãŒãã®æå³ A period NULL åç¬ã§ AND B user_attribute g1 ã°ã«ãŒã g1 å
ã§ OR C payment_attribute g1 ã°ã«ãŒã g1 å
ã§ OR è©äŸ¡ãšã³ãžã³ã®å
¥åã¯ãå
ã«æãã4 ã€ã®ã¬ã€ã€ãŒã®æ
å ±ã1ã€ã«æãã EvaluationData ã§ããConditionEvaluator åŽããã¯ãããããèªãã°å€å®ã«å¿
èŠãªå€ã¯ããã£ãŠããã ç¶æ
ã§åç
§ã§ããããã«ããŠãããŸããPoC ã§ã¯ããã«ãã£ã³ããŒã³åºæã®èšç®çµæãæãããæ¡ãæ€èšããŠããŸããããæ¬å®è£
ã§ã¯ãæ¡ä»¶è©äŸ¡ã®ãã§ãŒãºãšã¢ã¯ã·ã§ã³å®è¡ã®ãã§ãŒãºã§è²¬åãåããã¹ãããšå€æãã EvaluationData ã¯æ¡ä»¶è©äŸ¡ã«å¿
èŠãªæ
å ±ã ãã«çµã£ãŠããŸãã è©äŸ¡ãšã³ãžã³æ¬äœã¯ãConditionType ããšã®åå¥å€å®ãæ
ã ConditionEvaluator ãšãã«ãŒã« 1 ä»¶åã®çåœããŸãšãã RuleEvaluator ã® 2 æ®µæ§æã§ãã äžæ®µã® ConditionEvaluator ã¯ãConditionType ããšã« 1 ã€ãã€å®è£
ãçšæãããŠããã EvaluationData ãèªã¿åã£ãŠãã®æ¡ä»¶ 1 ä»¶åã®çåœãè¿ããŸããå€å®ã¯å¯äœçšãæãããå€éš API åŒã³åºãã DB æžã蟌ã¿ã¯èµ·ãããŸããã äžæ®µã® RuleEvaluator ã¯ããã®äžã«ä¹ã£ãŠã«ãŒã« 1 ä»¶åã®è©äŸ¡ãçµã¿ç«ãŠãŸããå
·äœçã«ã¯ã(1) RuleCondition ã®åè¡ããã® ConditionType ã«å¿ãã ConditionEvaluator ã«æ¯ãåãã(2) åè¡ãè¿ããçåœã ConditionGroup ã®ã»ãã³ãã£ã¯ã¹ (NULL ã¯åç¬ ANDãåãå€ã©ãã㯠ORãå¥ã®å€ã©ãã㯠AND) ã§ AND/OR åæãã(3) ã«ãŒã« 1 ä»¶åã®æçµçãªçåœãšãã©ã®æ¡ä»¶ãã©ãå¯äžãããã®å
èš³ãè¿ããŸããè¿ãã®ã¯çåœãšå
èš³ã ãã§ãèšç®çµæãå¯äœçšã¯å«ããŸããã æ°ããè©äŸ¡è»žãå¿
èŠã«ãªã£ããšãã¯ã察å¿ãã ConditionEvaluator ãå®è£
ã㊠ConditionType ã® enum ã«ç»é²ããŸããäžåºŠã«ã¿ãã°ã«å ããã°ã以éã®ãã£ã³ããŒã³å®çŸ©ã¯ RuleConditions ã® 1 è¡ãšããŠãã®è»žãèšå®å€ããŒã¹ã§åŒã³åºããŸãã ActionExecutor â äœãããã ãããããã«ãŒã«ã«å¯Ÿå¿ãã Action ãã ActionType ããšã® Executor ãå®è¡ããŸããäžéèšç®ããã€ã³ãä»äžã¹ããŒã¿ã¹ã®é·ç§»ããã€ã³ãå°åž³ãžã®æžã蟌ã¿ãå€éšãžã®ã€ãã³ãçºè¡ãšãã£ãå¯äœçšã¯ãããã§èµ·ãããŸããCondition / Rule åŽã¯å¯äœçšãæããªãèšèšãªã®ã§ãå€éšã«äœçšããããžãã¯ã¯ãã®å±€ã«éçŽãããŸããæ°ãã Action çš®å¥ãå¿
èŠã«ãªã£ããšãã¯ã察å¿ãã Executor ãå®è£
ã㊠ActionType ã® enum ã«ç»é²ããŸããäžåºŠã«ã¿ãã°ã«å ããã°ã以éã®ãã£ã³ããŒã³å®çŸ©ã¯ CampaignRules.ActionType ãš ActionParams ãæå®ãã圢ã§ããã® Action ãæ±çšçã«åŒã³åºããŸãã 3 è»žãæ¯ããå
±éãã«ã㌠Executor ã®è²¬åã¯ãAction ããšã®å¯äœçšãã®ãã® (DB æžã蟌ã¿ãå€éš API åŒã³åºããPointStatus ã®é·ç§»ãªã©) ã§ããäžæ¹ã§ããã€ã³ãèšç®ãš Cap (äžé) é©çšãPointStatus / ProvisionStatus ã®ã©ã€ããµã€ã¯ã«ç®¡çãå€éšãã€ã¯ããµãŒãã¹ã«æž¡ãåªçããŒã®çæãèšå®å€ãã³ãã¬ãŒãã®å±éãšãã£ããAction çš®å¥ããŸããã§æ¯åå¿
èŠã«ãªã暪æçãªåŠçãã¯ã3 軞ãšã¯å¥ã¬ã€ã€ãŒã®å
±éãã«ããŒã«åãåºããŠããŸããå Executor ã¯ãèªåã® Action ã«å¿ããŠå¿
èŠãªãã«ããŒã ããå¿
èŠãªãšãã«åŒã³åºã圢ã«ããŠãããŸããå®è£
ãããã«ããŒã¯ããã€ããããŸããã代衚äŸã 2 ã€æããŸãã PointLifecycleManager (PointStatus / ProvisionStatus ã®ãªãŒã±ã¹ãã¬ãŒã·ã§ã³) ãã€ã³ãä»äžã«ãŸã€ããã©ã€ããµã€ã¯ã«ããŸãšããŠæ±ããã«ããŒã§ãã ã客ããŸãžã®ãã€ã³ãä»äžç¶æ
(PointStatus) ãšã äŒèšäžã®åŒåœç¶æ
(ProvisionStatus) ã¯ãããããç¬ç«ããã¹ããŒããã·ã³ãšããŠè¡šçŸããŠããŸãã äžã PointStatus ã§ã planned ã§å°åž³ã«äºå®ãç«ãŠãå€éšã®ä»äž API ãæåãããš confirmed ãåŸåŠçãŸã§çµãããš completed ã«é²ã¿ãŸãã planned çŽåŸã«ãã£ã³ã»ã«ãããå Žå㯠cancelled ãå€éšåŒã³åºãã倱æããå Žå㯠failed ã«åããããšããã®ãäž»ãªé·ç§»ã§ããäžã ProvisionStatus ã§ãåŒåœãç«ã£ãŠããªã not_linked ãããåŒåœãçŽã¥ãã linked ãçµãŠãæçµçã« revoked (åŒåœåŠçã確å®ããç¶æ
) ã«é·ç§»ããã®ã䞻軞ã§ãã æ§ã¡ã«ã«ãŒããã€ãã©ã€ã³ã§ã¯ãPointStatus ã®é·ç§»ãš ProvisionStatus ã®é·ç§»ããããããã€ã³ãä»äžåŠçåŽãšåŒåœåŠçåŽã«åæ£ããŠå®è£
ãããŠããŠãäž¡è
ãã©ãé£åããŠãããã®èŠéããæªããªã£ãŠããŸãããRulebase åºç€ã§ã¯ãäž¡æ¹ã®ã¹ããŒããã·ã³ã PointLifecycleManager é
äžã«åãåºãã CompletePoint / ReversePoint / CreateProvision / UpdateProvision / RevokeProvision ã®å Action ããå¿
èŠãªãšãã«åŒã³åºã圢ã«ããŠãããŸããããã«ãã£ãŠãè€æ°æã«ãŸãããåŒåœãå¿
èŠãªã¡ã«ã«ãŒãç³»ã®ãã£ã³ããŒã³ããåŒåœãäžèŠãªã·ã³ãã«ãªãã£ã³ããŒã³ããåãéšåã®çµã¿åããã§ã©ã€ããµã€ã¯ã«ã衚çŸã§ããŸãã TemplateExpander (èšå®å€ãã³ãã¬ãŒãã®å±é) æ§ã·ã¹ãã ã«ã¯æ±çšçãªæååãã³ãã¬ãŒãã®ä»çµã¿ããªããããšãã°äŒèšã³ãŒããæ±ºæžçš®å¥ããšã«åããŠç©ããããªèŠä»¶ãåºãŠãããšãäŒèšã³ãŒãã®ãã¿ãŒã³æ°ã ããã£ã³ããŒã³ã¬ã³ãŒããå¥ã«åããããããŸããã§ãããæ¬æ¥ 1 ã€ã®ãã£ã³ããŒã³ãšããŠæ±ããããã®ããã¿ãŒã³æ°ã ãéè€ç»é²ããå¿
èŠããããéçšè² è·ã®åå ãšããŠç©ã¿äžãã£ãŠããéšåã§ãã ãããæ±çšåããããã«çšæããã®ã TemplateExpander ã§ãããã£ã³ããŒã³å®çŸ©ã®ãªãã« {user_id} / {campaign_id} / {payment_count} ãšãã£ããã¬ãŒã¹ãã«ããŒãæžããŠãããšãå®è¡æã« EvaluationData ããåãåºããå®å€ã«çœ®ãæããŸããäŒèšã³ãŒã (ããšãã° merpay_xxx_campaign-{campaign_id}-{user_status} ) ããããã·ã¥ã®ã·ãŒãæåå ( {user_id}:{campaign_id}:{payment_count} ) ãªã©ããã®å©çšäŸã§ããæ°ãããã¿ãŒã³ãå¿
èŠã«ãªã£ããšãããèšå®ãã¹ã¿åŽã®ãã³ãã¬ãŒãæååãå·®ãæ¿ããã°ãã³ãŒã倿Žã远å ã¬ã³ãŒããªãã«åäžãã£ã³ããŒã³ã®äžã§æ±ããŸãã æåã®å®è£
äºäŸ: ã³ãŒã決æžã®åæ°é£åãã£ã³ããŒã³ ãããŸã§ã«äœã£ãæ±çšåºç€ã®ãå
¥ãç©ãã䜿ã£ãæåã®ç§»è¡ã§ãããæèŠçã«ã¯ããªã¹ã¯ãäœããéçšè² è·ã®é«ããšããã ããå§ããããªããŸããæ°ããã§èç©ããŒã¿ã®å°ãªããã®ã»ã©ç§»è¡ãªã¹ã¯ãäžãããéçšè² è·ãé«ãã»ã©ç§»è¡ã®å¹æãåºãããããã§ããåœåã¯ã¡ã«ã«ãªã¢ãã€ã«åããã£ã³ããŒã³ãæåã®ç§»è¡å¯Ÿè±¡ã«æ®ããäºå®ã§ãããå
ã
ãããã¢ãŒããã¯ãã£å·æ°ã®ãã£ããã«ããæ¡ãæãã£ãŠããŸãããã皌åéå§ããæ¥ãæµ
ãèç©ããŒã¿ãå°ãªãäžæ¹ã§ 12 ãã¿ãŒã³ã®æ¯æéçšã§éçšè² è·ãé«ãããšãããŸãã«ã¹ã€ãŒãã¹ãããã®æ¡ä»¶ã«åœãŠã¯ãŸã£ãŠããããã§ãã ãã ãã¡ããã©ãã®ã¿ã€ãã³ã°ã§ãæ°èŠäŒç»ãšããŠãã³ãŒã決æžã®åæ°é£åãã£ã³ããŒã³ã ã®è©±ãç«ã¡äžãããŸããæ°èŠäŒç»ã§ããã°ãåžžæçšŒåããŠããæ¢åãã€ãã©ã€ã³ãæ¢ããã«èŒãæ¿ããããšããã³ã¹ããæããã«ãæå°æ§æã§ãèšå®å€ããŒã¹ã§ãã£ã³ããŒã³ãçµã¿ç«ãŠãã ããšã®æ€èšŒãã§ããŸããçµæãšããŠãæåã®äºäŸã¯ç§»è¡ã§ã¯ãªããŒãããã®ç«ã¡äžãã«æ¯ãçŽããæ¬äŒç»ã®ãã£ã³ããŒã³ã Rulebase äžã§çŽæ¥ç«ã¡äžãã圢ã§é²ããŸãããæ¢åã®ã¡ã«ã«ãªã¢ãã€ã«ãªã©ã®ç§»è¡ã¯ãå
ã®ãã§ãŒãºã«æã¡è¶ããŠããŸãã ãã®æ°èŠäŒç»ã¯ãN åå©çšããããšã«ä»äžãçºç«ããã·ã³ãã«ãªä»çµã¿ã§ãã客ããŸããèŠããšã䜿ãç¶ããã»ã©ã確å®ã«å€åŒããè¿ã£ãŠãããäœéšã«ãªããŸãã ãããRulebaseäžã§çµãã«ããã£ãŠå¿
èŠã ã£ãã®ã¯ 环èšã«ãŠã³ããšåšæå ±é
¬ãæ±ã ActionType ïŒ COUNT_AND_REWARD ïŒã 1 ã€ã ã远å ããããšã ãã§ãããããšã¯ æ¢åã® ConditionType (æé / ã客ããŸå±æ§ / 決æžå±æ§) ã®çµã¿åããã§å®è£
ã§ããç¹ã§ããRulebase äžã§ãã«ãŒã«è©äŸ¡ãšã¢ã¯ã·ã§ã³å®è¡ãæå€§éåå©çšãããªãã¹ãèšå®å€ã ãã§çµã¿ç«ãŠãã圢ããæåã«æ€èšŒã§ããã±ãŒã¹ã«ãªããŸããã ä»çµã¿èªäœã¯ã·ã³ãã«ã§ããã客ããŸã®ãšã³ããªç¶æ³ããã客ããŸå±æ§æ¡ä»¶ãã§èŠãŠã察象決æžããæ±ºæžå±æ§æ¡ä»¶ãã§çµã蟌ãã ããã§ã COUNT_AND_REWARD Executor ãã«ãŠã³ã¿ãã€ã³ã¯ãªã¡ã³ãããŸããã«ãŠã³ã¿ãèŠå®åæ°ã«éãããšãã€ã³ããä»äžããŠã«ãŠã³ã¿ããªã»ããããããããã£ã³ããŒã³æéäžãã£ãšç¹°ãè¿ãããšããæµãã§ããããŒã¿ãšããŠã¯ãCampaigns 1 è¡ãCampaignRules 1 è¡ãRuleConditions æ°è¡ããšããã·ã³ãã«ãªæ§é ã§è¡šçŸã§ããŸã (ç°¡ç¥åããã€ã¡ãŒãž)ã // Campaigns { "campaign_id": "...", "campaign_type": 9, // InfinitePayment "start_at": "2026-04-01", "end_at": "2026-09-30", "metadata": { ... } } // CampaignRules (1 ä»¶) { "trigger_type": "PaymentCharge", "action_type": "COUNT_AND_REWARD", "action_params": { "trigger_count": 3, "reward_currency_points": 100 } } // RuleConditions (3 ä»¶: æé / ãšã³ããªç¶æ³ / 決æžçš®å¥) { "condition_type": "period", "params": { ... } } { "condition_type": "user_attribute", "params": { "attribute": "entry_status", "promotion_key": "..." } } { "condition_type": "payment_attribute", "params": { "attribute": "transaction_type", "value": "code_payment" } } å®è£
äžã®æ°èŠè¿œå 㯠COUNT_AND_REWARD Executor ãšãã«ãŠã³ã¿ãä¿æãã 2 ã€ã®ããŒãã« (çŸåšã®ã«ãŠã³ããšãã°) ãããã§ããä»ã¯åºç€ã®æ±çšéšåããã®ãŸãŸçµã¿åãããŠå®çµããŸããã è£è¶³ãšããŠããã®åæ°é£åãã£ã³ããŒã³ã®æçŸ©ã¯ãåçŽãªãã£ã³ããŒã³æŽŸçãããããããªã£ããããšã§ã¯ãããŸãããSQL INSERT ã§äŒŒããã£ã³ããŒã³ãå¢ããããšèªäœã¯ãåŸæ¥ã®å°çšãã€ãã©ã€ã³æä»£ã§ããããªãã«ã§ããŠããŸãããRulebase åºç€ã§æ°ããå¯èœã«ãªã£ãã®ã¯ãCampaignType ããŸããã Ruleã»Action ã®èšå®ããŒã¹åå©çšã§ããäžåºŠå®è£
ãã Condition ã Action ã¯ãå¥ã® CampaignType ã®ãã£ã³ããŒã³ãããèšå®å€ã®çµã¿åããã§åŒã³åºããŸããåæ°é£åãã£ã³ããŒã³ã§äœ¿ã£ã COUNT_AND_REWARD ããä»ã®ãã£ã³ããŒã³ãã环ç©åæ°ã§çºç«ãããèŠä»¶ãæãŠã°ãã³ãŒããæžãè¶³ããã«èšå®ã ãã§äœ¿ãåããŸãã åãä»çµã¿ã¯ãåçãªæ¡ä»¶åå²ã 1 ã€ã®ãã£ã³ããŒã³èšå®ã§è¡šçŸããããšã«ã転çšã§ããŸããããšãã°ã¡ã«ã«ãªã¢ãã€ã«åããã£ã³ããŒã³ã§ã¯ã3 ã¹ããŒã¿ã¹ à 4 ããŒã¿ãã©ã³ãã 12 åã®ç¬ç«ãã£ã³ããŒã³å®çŸ©ãšããŠæ¯ææºåããŠããŸããããRulebase ãªã屿§æ¡ä»¶ã»ç¹°ãè¿ãæ¡ä»¶ã»äžéæ¡ä»¶ãçµã¿åãã㊠1 ã€ã®ãã£ã³ããŒã³èšå®ã®äžã§è¡šçŸã§ããŸãããN åããšã«çºç«ãã®ãããªåšæçãªæ¯ãèããã COUNT_AND_REWARD ã Executor åŽã«æã€ããšã§æ±çšããŒããšããŠæ±ããŸããä»åŸã®æ°äŒç»ã§ã¯ãæ¢åã®ã«ãŒã«ã»ã¢ã¯ã·ã§ã³ã®çµã¿åããã§è¡šçŸã§ããç¯å²ãåºãã£ãŠãããããããŒãããã®å®è£
ã§ã¯ãªããèšå®å€ã ãã§äœã£ãŠè©Šãããšããããå
¥ããããšããã®ãæ°åºç€ã®æå€§ã®ã¡ãªããã§ãã äœè«: ã©ã³ãã ãªã®ã«ãäœåºŠåŒããŠãåãéé¡ ä»æ§ãšããŠã¯ ãèŠå®åæ°ã«å°éããããè€æ°ã®åè£éé¡ããéã¿ä»ãã©ã³ãã ã§ 1 ã€ãåŒãåœãŠãã ãšããèŠä»¶ããããŸããçŽ çŽã« math/rand ã§æœéžããŠããŸããšãPub/Sub ã® at-least-once é
ä¿¡äžã§ã¯åã PaymentCharge ãåé
ä¿¡ããããšãã« 1 åç®ãš 2 åç®ã§å¥ã®éé¡ãéžã°ããŠããŸãããšããããŸããPointID ããŒã¹ã®åªçæ§ãã§ãã¯ã¯éã£ãŠããã®ã«ã2 åç®ã®è©Šè¡ããèŠããéé¡ãååä»äžé¡ãšãããããšããã±ãŒã¹ãèµ·ãããæ§é ã§ãã ããã§æœéžã¯ä¹±æ°ã§ã¯ãªã決å®è«çããã·ã¥ã§è¡ããŸããã user_id ã»ãã£ã³ããŒã³èå¥åã» payment_count ãçµã¿åãããæååãã·ãŒãã«ãSHA-256 ã§ããã·ã¥åãããã®ããéã¿ä»ãã§åè£ã 1 ã€éžã³ãŸããã¢ã«ãŽãªãºã ã®æŠç¥ã¯æ¬¡ã®ãšããã§ã (ç°¡ç¥åããã€ã¡ãŒãž)ã // seed ã®äŸ: "12345:campaign-abc:3" (user_id : campaign_id : payment_count) seed, _ := expander.Expand(params.DeterministicReward.SeedFormat) h := sha256.Sum256([]byte(seed)) v := binary.BigEndian.Uint64(h[0:8]) // å
é 8 ãã€ãã uint64 ãšããŠåãåºã var totalWeight uint64 for _, rv := range variations { totalWeight += rv.Weight } target := v % totalWeight // éã¿ã®åèšã§å²ã£ãäœã (ãããåè£éžæçšã®å€) var cumulative uint64 for i, rv := range variations { cumulative += rv.Weight if target < cumulative { return rv, i // 环ç©éã¿ã§åœãã£ãåè£ãéžæ } } ã客ããŸããèŠãã䜿ããã³ã«éãéé¡ãè¿ã£ãŠãããäœéšã¯ãã®ãŸãŸã«ãåã (user_id, campaign_id, payment_count) ã®çµã¿åããã«å¯ŸããŠã¯äœåºŠ retry ãèµ°ã£ãŠããå¥ããã»ã¹ããèªãŸããŠããåãéé¡ãäžæã«ç¢ºå®ããŸãã ãããŠãã·ãŒãããæãã°æœéžçµæã¯ç¢ºå®å€ãªã®ã§ãPub/Sub ã®ã€ãã³ãåŠçå®äºãåŸ
ããã«ãä»åä»äžãããéé¡ããèšç®ã§ããŸããæ±ºæžæåçŽåŸã® API ã¬ã¹ãã³ã¹ãããã³ããšã³ãåŽã§ãä»å㯠â ãã€ã³ãã§ãããšç¢ºå®è¡šç€ºãè¿ãããšãã§ããåŸæ®µã§ UserPoints ãæžãããããšã«éé¡ãå€ãã£ãŠèŠããããšãã£ãäžæŽåã®å¿é
ããããŸãããat-least-once ãš weighted random ãäž¡ç«ãããããã®ä»çµã¿ããã客ããŸãžã®æ©ã衚瀺ã«ããã®ãŸãŸäœ¿ãã圢ã«ãªã£ãŠããŸãã QA ç°å¢ã®æ¹åã«å©ãããã話 ä»åã® QAã§ã¯ããã€ãã®ç°å¢ãã¿ãŒã³ãåãæ¿ããŠå®æœããå¿
èŠããããå·¥æ°ããªã¥ãŒã ã«äžå®ãæããŠããŸãããã¡ããã©è¯ãã¿ã€ãã³ã°ã§ä»ãŸã§ Santa ãµãŒãã¹ã§ã¯å®çŸã§ããŠããªãã£ããã€ãã³ãé§åéšåå°çšã® QA è€è£œç°å¢ããããŒã ã¡ã³ããŒãäœããã£ãŠãããããšã§ã䞊è¡ã㊠QA ã宿œã§ããããã«ãªãã倧å€å©ãããŸããããã®è©³çŽ°ã¯æ¬é£èŒ 8 æ¥ç®ã® @mikupo ã®èšäº ã§è©³ãã解説ãããŠããŸãã ãããã« ä»åã®ãªãã¡ã¯ã¿ãªã³ã°ã§ã¯ãããã£ã³ããŒã³å®çŸ©ãã³ãŒãããããŒã¿ãžã ãšããæ¹éã®ããšã3 ããŒãã« + è©äŸ¡ãšã³ãžã³ã«åæ§æããŸãããããŒã³ã責任ãšã®äž¡ç«ã§å幎å¯ãããŠãããªãã¡ã¯ã¿ãªã³ã°ã®æ©äŒã諊ããã«æŽãã§ãå
¥ãç©ããäœãåã£ãŠæ¬çªã§ãã£ã³ããŒã³ãã²ãšã€çšŒåãããããšã§ãã·ã¹ãã ã«ä»åŸã®æ°èŠä»¶ã«ã€ããŠã®åãç¿ãäœãããšãã§ããŸããã ãã ããåæ°é£åãã£ã³ããŒã³èªäœã¯æ¬èšäºå·çæç¹ã§ã¯ããŒã³ãããã°ããã§ããŸã 掟çãã£ã³ããŒã³ã®å®äŸã¯ãããŸãããèšå®ã ãã§æŽŸçãç«ã¡äžããäžçã®æ¬æ Œæ€èšŒã¯ãããããã®æ°äŒç»ãéããŠè¡ã£ãŠãããã§ãŒãºã§ããå ããŠãã¡ã«ã«ãŒãåžžæéå
ãªã©ã®æ¢åã®ãã€ãã©ã€ã³ããŸã 皌åããŠãããTemporary ããããæ¬çªã«æ®ã£ããŸãŸã§ããåžžæçšŒåãããã£ã³ããŒã³ã·ã¹ãã ã§ã¯ãå
¥ãç©ãäœãé£ããããããæ¢ããã«èŒãæ¿ããã¿ã€ãã³ã°ãšæé ã®èšèšããããããããå
ã®æ¬é¡ã«ãªããŸãã ä»åã®èšäºã¯ä»¥äžã«ãªããŸãããªã«ãåèã«ãªãããšãããã°å¹žãã§ãã æ¬¡ã®èšäºã¯ orfeon ããã®ãTiDB / AlloyDB ã®å€§èŠæš¡ããŒãã«ãé«éã«BigQueryniåæããããã®å·¥å€«ãã§ããåŒãç¶ããæ¥œãã¿ãã ããã