I would actually use a flag on each email record in the database:
Your worker (or multiples) update the oldest record with their unique worker ID (e.g. a PID or IP/PID combination).
Example for Oracle SQL:
update email set workerid = 'my-unqiue-worker-id' where emailid in (
select emailid from email where
rownum <= 1 and
duetime < sysdate and
workerid = null
order by duetime
)
This would just take 1 not yet processed record (ordered by duetime
, which has to be in the past) and set the worker ID. This procedure would be synchronized by the normal database locking mechanism (so only one thread writes at the same time).
Then you select all records with:
select * from email where workerid = 'my-unique-worker-id'
which will be either 0 or 1 record. If it is 0, there is no due mail.
If you have finished sending the email you set the workerid = 'some-invalid-value'
(or you use another flag-column to mark the progress. That way it doesn't get picked up by the next worker.
You probably won't be able to find out if the email really has been sent. If the worker dies after sending and before updating the record, there's not much you can do. To be a bit more self-sufficient the worker could create a process file locally (e.g. an empty file with the emailid
as the file name. This could at least detect if the crash was just a database connection issue..
If the worker is started and before updating any record already finds a message, which has its ID as the workerid
then I would raise an alert / error which should be handled manually (by checking the SMTP server log and manually updating the record).