The MessageID precision issue is a great catch; it's the kind of bug that never shows up in testing with three rows. One more pitfall worth checking with LockService: a run that dies mid-batch (the six-minute execution limit is the usual culprit) leaves rows stuck in SENDING forever. Storing a timestamp alongside the claim lets a later run or a small daily report surface rows that have been SENDING for more than, say, an hour, so a person can check the provider log instead of guessing. Processing in small batches and calling flush after each claim also keeps you well clear of the time limit.
Agreed, and surfacing is the right call rather than releasing. If the run died after the provider had already accepted the message, putting the row back in the queue would send it twice. A timestamp on SENDING plus a daily list of rows stuck for more than an hour, checked against the provider log by CustomID, covers it, and small batches with a flush after each claim keep most runs from dying there in the first place.
Claiming the row before sending is the right pattern. Without it, two triggers overlapping is all it takes to double send to the same person. A status column plus a timestamp also gives you a cheap audit log.
Yunus Emre Vurgun
Writing about AI agents, hardware, and practical software.
The MessageID precision issue is a great catch; it's the kind of bug that never shows up in testing with three rows. One more pitfall worth checking with LockService: a run that dies mid-batch (the six-minute execution limit is the usual culprit) leaves rows stuck in SENDING forever. Storing a timestamp alongside the claim lets a later run or a small daily report surface rows that have been SENDING for more than, say, an hour, so a person can check the provider log instead of guessing. Processing in small batches and calling flush after each claim also keeps you well clear of the time limit.