|
|
|
@ -6,6 +6,7 @@ import logging
|
|
|
|
|
import os
|
|
|
|
|
import random
|
|
|
|
|
from signal import SIGTERM
|
|
|
|
|
from uuid import uuid4
|
|
|
|
|
|
|
|
|
|
import gevent.event
|
|
|
|
|
|
|
|
|
@ -128,6 +129,21 @@ def writeall(write, value):
|
|
|
|
|
value = value[n:]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def atomic_write(filepath, content):
|
|
|
|
|
"""Writes content to filepath atomically, ie. replacing the file in one step
|
|
|
|
|
without potential for partial write. content may be str or bytes.
|
|
|
|
|
If the file already exists, it will silently do nothing as it is assumed a given
|
|
|
|
|
filename can only ever contain the same content.
|
|
|
|
|
"""
|
|
|
|
|
if isinstance(content, str):
|
|
|
|
|
content = content.encode("utf-8")
|
|
|
|
|
temp_path = "{}.{}.temp".format(filepath, uuid4())
|
|
|
|
|
ensure_directory(filepath)
|
|
|
|
|
with open(temp_path, 'wb') as f:
|
|
|
|
|
writeall(f.write, content)
|
|
|
|
|
rename(temp_path, filepath)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def serve_with_graceful_shutdown(server, stop_timeout=20):
|
|
|
|
|
"""Takes a gevent.WSGIServer and serves forever until SIGTERM is received,
|
|
|
|
|
or the server errors. This is slightly tricky to do due to race conditions
|
|
|
|
|