Consider a chat bot written as an AWS Lambda function. It gets invoked via HTTP requests from a 3rd party service, the chat service into which it is integrated. Now, that 3rd party API is a bit… quirky. The main issue with it is: it requires an authentication token to interact with, but only one token can exist at any one time. The way it works is:
- Bot creates a request to
POST /authwith a bunch of secret information, and gets returned a token in response. - Bot then makes a request to
POST /messageswithAuthorization: Bearer <token>to post messages to the chat. - Tokens expire after some hours.
The crux is that a POST /auth request resets any previous token and invalidates all other clients which hold tokens. There is no GET /auth or similar to get existing tokens.
This now becomes a coordination problem between concurrent instances of randomly spawned bots. They all need to use the same token, but will generate tokens independently. I'm not terribly keen on introducing some singleton service whose task it would be to only coordinate the token, I'd like to keep the independently-scaling Lambda paradigm. I'm using DynamoDB to store tokens to try to coordinate them between bot instances, but still have edge case race conditions which can require up to three retries to get tokens settled.
The worst case is an invalid token stored in DynamoDB and two bots being instantiated simultaneously:
- both will read the invalid token
- both will attempt requests which fail
- both will try to read the token again, since another bot may have refreshed it in the meantime
- both will discard the token which is known to be bad
- both will generate a new token and store it, one of them randomly "winning"
- the "loser" will be doing another bad request and repeat the previous steps
Ideally there would be a lockable resource which one bot can lock and generate a token, and others can wait for. But AFAIK DynamoDB doesn't have that kind of functionality.
What is a good pattern and/or AWS service to coordinate such a singleton token between independent, parallel Lambda instances?