mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Merge pull request #1220 from benoitc/fix/host-restart-uds
Fix/host restart uds
This commit is contained in:
commit
d4e1abd84b
@ -4,6 +4,7 @@
|
||||
# See the NOTICE for more information.
|
||||
|
||||
import errno
|
||||
import fcntl
|
||||
import os
|
||||
import socket
|
||||
import stat
|
||||
@ -105,6 +106,8 @@ class UnixSocket(BaseSocket):
|
||||
raise ValueError("%r is not a socket" % addr)
|
||||
self.parent = os.getpid()
|
||||
super(UnixSocket, self).__init__(addr, conf, log, fd=fd)
|
||||
# each arbiter grabs a shared lock on the unix socket.
|
||||
fcntl.lockf(self.sock, fcntl.LOCK_SH | fcntl.LOCK_NB)
|
||||
|
||||
def __str__(self):
|
||||
return "unix:%s" % self.cfg_addr
|
||||
@ -117,9 +120,17 @@ class UnixSocket(BaseSocket):
|
||||
|
||||
|
||||
def close(self):
|
||||
super(UnixSocket, self).close()
|
||||
if self.parent == os.getpid():
|
||||
os.unlink(self.cfg_addr)
|
||||
# attempt to acquire an exclusive lock on the unix socket.
|
||||
# if we're the only arbiter running, the lock will succeed, and
|
||||
# we can safely rm the socket.
|
||||
try:
|
||||
fcntl.lockf(self.sock, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
os.unlink(self.cfg_addr)
|
||||
super(UnixSocket, self).close()
|
||||
|
||||
|
||||
def _sock_type(addr):
|
||||
|
||||
56
tests/test_sock.py
Normal file
56
tests/test_sock.py
Normal file
@ -0,0 +1,56 @@
|
||||
import fcntl
|
||||
|
||||
try:
|
||||
import unittest.mock as mock
|
||||
except ImportError:
|
||||
import mock
|
||||
|
||||
from gunicorn import sock
|
||||
|
||||
|
||||
@mock.patch('fcntl.lockf')
|
||||
@mock.patch('socket.fromfd')
|
||||
def test_unix_socket_init_lock(fromfd, lockf):
|
||||
s = fromfd.return_value
|
||||
sock.UnixSocket('test.sock', mock.Mock(), mock.Mock(), mock.Mock())
|
||||
lockf.assert_called_with(s, fcntl.LOCK_SH | fcntl.LOCK_NB)
|
||||
|
||||
|
||||
@mock.patch('fcntl.lockf')
|
||||
@mock.patch('os.getpid')
|
||||
@mock.patch('os.unlink')
|
||||
@mock.patch('socket.fromfd')
|
||||
def test_unix_socket_close_delete_if_exlock(fromfd, unlink, getpid, lockf):
|
||||
s = fromfd.return_value
|
||||
gsock = sock.UnixSocket('test.sock', mock.Mock(), mock.Mock(), mock.Mock())
|
||||
lockf.reset_mock()
|
||||
gsock.close()
|
||||
lockf.assert_called_with(s, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
unlink.assert_called_with('test.sock')
|
||||
|
||||
|
||||
@mock.patch('fcntl.lockf')
|
||||
@mock.patch('os.getpid')
|
||||
@mock.patch('os.unlink')
|
||||
@mock.patch('socket.fromfd')
|
||||
def test_unix_socket_close_keep_if_no_exlock(fromfd, unlink, getpid, lockf):
|
||||
s = fromfd.return_value
|
||||
gsock = sock.UnixSocket('test.sock', mock.Mock(), mock.Mock(), mock.Mock())
|
||||
lockf.reset_mock()
|
||||
lockf.side_effect = IOError('locked')
|
||||
gsock.close()
|
||||
lockf.assert_called_with(s, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
unlink.assert_not_called()
|
||||
|
||||
|
||||
@mock.patch('fcntl.lockf')
|
||||
@mock.patch('os.getpid')
|
||||
@mock.patch('socket.fromfd')
|
||||
def test_unix_socket_not_deleted_by_worker(fromfd, getpid, lockf):
|
||||
fd = mock.Mock()
|
||||
gsock = sock.UnixSocket('name', mock.Mock(), mock.Mock(), fd)
|
||||
lockf.reset_mock()
|
||||
getpid.reset_mock()
|
||||
getpid.return_value = mock.Mock() # fake a pid change
|
||||
gsock.close()
|
||||
lockf.assert_not_called()
|
||||
Loading…
x
Reference in New Issue
Block a user