Skip to content

Commit 1006005

Browse files
🐛 Serialize mail actions
1 parent 3bdb84f commit 1006005

File tree

2 files changed

+32
-23
lines changed

2 files changed

+32
-23
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
1212

1313
## Fixed
1414
- `sample.env` now contains the actual names of the environment variables.
15+
- Serialization for mail-related processing to avoid duplicate work and race
16+
conditions
1517

1618
## Changed
1719
- Format of PGP Timestamper request mail message (ISO 8601 format)

autoblockchainify/mail.py

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import autoblockchainify.config
3838

3939
logging = _logging.getLogger('mail')
40+
serialize_receive = threading.Lock()
41+
serialize_create = threading.Lock()
4042

4143

4244
def split_host_port(host, default_port):
@@ -285,27 +287,31 @@ def check_for_stamper_mail(imap, stat, logfile):
285287

286288

287289
def wait_for_receive(logfile):
288-
stat = logfile.stat() # Should always succeed
289-
logging.debug("Timestamp revision file is from %d" % stat.st_mtime)
290-
(host, port) = split_host_port(autoblockchainify.config.arg.stamper_imap_server, 143)
291-
with IMAP4(host=host, port=port) as imap:
292-
imap.starttls()
293-
imap.login(autoblockchainify.config.arg.stamper_username,
294-
autoblockchainify.config.arg.stamper_password)
295-
imap.select('INBOX')
296-
if not check_for_stamper_mail(imap, stat, logfile):
297-
# No existing message found, wait for more incoming messages
298-
# and process them until definitely okay or giving up for good
299-
if 'IDLE' in imap.capabilities:
300-
imap_idle(imap, stat, logfile)
301-
else:
302-
logging.warning("IMAP server does not support IDLE")
303-
# Poll every minute, for 10 minutes
304-
for i in range(10):
305-
time.sleep(60)
306-
if check_for_stamper_mail(imap, stat, logfile):
307-
return
308-
logging.error("No response received, giving up")
290+
with serialize_receive:
291+
if not logfile.is_file():
292+
logging.warning("Logfile vanished. Double mail receive thread?")
293+
return
294+
stat = logfile.stat()
295+
logging.debug("Timestamp revision file is from %d" % stat.st_mtime)
296+
(host, port) = split_host_port(autoblockchainify.config.arg.stamper_imap_server, 143)
297+
with IMAP4(host=host, port=port) as imap:
298+
imap.starttls()
299+
imap.login(autoblockchainify.config.arg.stamper_username,
300+
autoblockchainify.config.arg.stamper_password)
301+
imap.select('INBOX')
302+
if not check_for_stamper_mail(imap, stat, logfile):
303+
# No existing message found, wait for more incoming messages
304+
# and process them until definitely okay or giving up for good
305+
if 'IDLE' in imap.capabilities:
306+
imap_idle(imap, stat, logfile)
307+
else:
308+
logging.warning("IMAP server does not support IDLE")
309+
# Poll every minute, for 10 minutes
310+
for i in range(10):
311+
time.sleep(60)
312+
if check_for_stamper_mail(imap, stat, logfile):
313+
return
314+
logging.error("No response received, giving up")
309315

310316

311317
def async_email_timestamp(resume=False):
@@ -333,8 +339,9 @@ def async_email_timestamp(resume=False):
333339
new_rev = ("git commit %s\nTimestamp requested at %s\n" %
334340
(head.target.hex,
335341
strftime("%Y-%m-%d %H:%M:%S UTC", gmtime())))
336-
with logfile.open('w') as f:
337-
f.write(new_rev)
342+
with serialize_create:
343+
with logfile.open('w') as f:
344+
f.write(new_rev)
338345
send(new_rev)
339346
threading.Thread(target=wait_for_receive, args=(logfile,),
340347
daemon=True).start()

0 commit comments

Comments
 (0)