Thank you to the folks letting me know that @RikerGoogling and @WorfEmail have been sometimes posting the same thing three times in a row. I figured out what went wrong and I've patched the program to fix it. Check below this post if you want to know the technical details.
THREAD
2. My bots all run on Amazon Web Services (AWS) Lambda, a system where you can upload some code to AWS and it will run the code on the schedule you provide. The logic for
@picardtips and
@RikerGoogling has been running on that system on Twitter for years without an issue. A little while ago I added automation for
@WorfEmail and
@LocutusTips which I have less content for, so Worf's and Locutus's posts happen every few days instead of every day. Adding those bots helped cause the repetition bug.
3. Riker and Worf were repeating themselves because AWS Lambda retries failures several times. The way my program works, Picard finishes his logic, either posting or deciding not to post, then Riker, then Worf, then Locutus. Moving my bots off Twitter to Mastodon and Bluesky was something I wanted to do quickly after my Twitter accounts started getting suspended, so I didn't bother writing unit tests for the new bots yet, thinking if they fail no one will notice but me. A mistake.
4. My first guess was that AWS Lambda had a scheduling bug. They've had them before. I checked the logs and saw the program running three times at the problem time instead of once. But I also noticed a NullPointerException in each execution log. NullPointerException is Java for "you done fucked up, A-A-Ron." First I thought Amazon was having an error and I was also causing an unrelated coincidental error, but no, this time it was all me. Amazon just retries the function if it throws an error.
5. In my function, that means Picard maybe posts, then Riker, then Worf, then Locutus. If Worf logic throws an error, Riker has already posted, and the whole function is going to run again because of the error, so Riker will post again before we hit the Worf error again. If Worf posts and then Locutus throws an error, same deal; the function will run again, Worf will post the same thing again, and Locutus will throw the error again. That's what happened.
6. This also explains why
@LocutusTips hasn't been posting yet. I've been waiting for it to post on schedule (once every few days) before announcing its existence, but it hasn't yet. The reason is that I scheduled Locutus to post on days when Worf doesn't, and vice versa. So on Locutus's posting days, Worf had no content for the day, and so threw a NullPointerException, halting the program before Locutus could get a chance to post.
7. So how do we fix the problem? Add some logic to check whether each bot has any content scheduled for today. If no content exists for today, don't assume there is any, don't try to get today's content for that bot. And for good measure, since I might add another bot into this function years from now and forget about this issue, wrap the whole function in a try-catch block to log any errors without reporting them as failures to AWS. Better too few posts on a bad day than a bunch of duplicates.
8. That last bit isn't a good practice in general, but for something like this, it doesn't have much downside really.