延續上次
[Python] Create thread, and receive signal to handle reload, shutdown
的需求,建立一個service,但這次不收signal, 而是改用socket接受reload和stop命令。
幾個重點:
1. 不會因為接收signal而中斷IO
2. 需要建立一個controller (client) 來對service發送指令
3. controller會等service確實執行完動作才退出,不像kill丟了signal就跑。
所以service在應該確保每次check socket之間不超過一定時間,萬一對controller下reload的另一端,有來自front end(UI)的request在等,request可能遇到timeout而被中斷。
4. 建立無檔案socket address,不用建檔砍檔也不用管檔案權限,但是只有Linux可用,MacOSx試過不行....
幾個重點:
1. 不會因為接收signal而中斷IO
2. 需要建立一個controller (client) 來對service發送指令
3. controller會等service確實執行完動作才退出,不像kill丟了signal就跑。
所以service在應該確保每次check socket之間不超過一定時間,萬一對controller下reload的另一端,有來自front end(UI)的request在等,request可能遇到timeout而被中斷。
4. 建立無檔案socket address,不用建檔砍檔也不用管檔案權限,但是只有Linux可用,MacOSx試過不行....
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# encoding: utf-8 | |
''' | |
usage: | |
python testNamedSocketClieht.py reload | |
python testNamedSocketClieht.py stop | |
''' | |
import socket | |
import sys | |
import time | |
server_address = '\x00testNamedSocket' | |
if len(sys.argv) == 2: | |
act = str(sys.argv[1]).lower() | |
if act in ['stop', 'reload']: | |
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | |
print 'connecting to %s' % server_address | |
try: | |
sock.connect(server_address) | |
except socket.error, msg: | |
print msg | |
sys.exit(1) | |
try: | |
print 'sending "%s"' % act | |
sock.sendall(act) | |
amount_received = 0 | |
amount_expected = len(act) | |
while amount_received < amount_expected: | |
data = sock.recv(16) | |
amount_received += len(data) | |
print 'received "%s"' % data | |
time.sleep(1) | |
finally: | |
print 'closing socket' | |
sock.close() | |
else: | |
print "Unknown command" | |
sys.exit(2) | |
sys.exit(0) | |
else: | |
print "usage: %s stop|reload" % sys.argv[0] | |
sys.exit(2) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# encoding: utf-8 | |
import time | |
import socket | |
import errno | |
''' | |
Put null character at beginning to open a | |
"Named Unix Socket", without opening file system path. | |
Only supported by Linux, not by Mac OSX. | |
''' | |
server_address = '\x00testNamedSocket' | |
class TestService(): | |
sock = None | |
connection = None | |
def __init__(self): | |
print 'init' | |
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | |
self.sock.bind(server_address) | |
self.sock.setblocking(0) | |
# 1 for only keep 1 message queued on buffer. | |
self.sock.listen(1) | |
def __del__ (self) : | |
print 'del' | |
if self.connection: | |
self.connection.close() | |
def delay_reload(self): | |
print 'reloading' | |
cnt = 5 | |
while cnt > 0: | |
print '.' | |
cnt -= 1 | |
time.sleep(1) | |
def delay_stop(self): | |
print 'stopping' | |
cnt = 10 | |
while cnt > 0: | |
print '.' | |
cnt -= 1 | |
time.sleep(1) | |
def check_socket(self): | |
try: | |
#sock.setblocking(0) will raise error 11 here. | |
self.connection, client_address = self.sock.accept() | |
print 'connection from %s' % client_address | |
data = self.connection.recv(16) | |
if not data: | |
print 'no data from %s' % client_address | |
return None | |
print 'received "%s"' % data | |
act = str(data).lower() | |
if act in ['stop', 'reload']: | |
return act | |
else: | |
#echo unsupported acts immediately | |
self.connection.sendall(data) | |
except socket.error, e: | |
if errno.EAGAIN == e.errno: | |
return None | |
else: | |
raise e | |
return None | |
def run(self): | |
while True: | |
print '-' | |
act = self.check_socket() | |
if 'reload' == act: | |
self.delay_reload() | |
self.connection.sendall(act) | |
elif 'stop' == act: | |
self.delay_stop() | |
self.connection.sendall(act) | |
break | |
else: | |
pass | |
time.sleep(2) | |
if __name__ == '__main__': | |
mainThread = TestService() | |
mainThread.run() |
留言
張貼留言