Add kill flag to AprsClient

When starting an AprsClient with AprsClient.run(...) the client enters
a loop without an exit condition (i.e. a while True loop).  If autoreconnect
is set to True, it is impossible to exit the aforementioned loop even if
AprsClient.disconnect() is called.

This causes problems when running the client in a thread (or as a
background service, etc.) as the process will not join nor terminate
unless explicitly shutdown with SIGKILL.

Minimal example:

```
import signal

from ogn.client import AprsClient
from ogn.parser import parse_aprs, parse_ogn_beacon, ParseError

def process_beacon(raw_message):
    print('Received message')

client = AprsClient(aprs_user='N0CALL')
signal.signal(signal.SIGTERM, lambda signo, stackno: client.disconnect())
client.connect()
client.run(callback=process_beacon, autoreconnect=True)
```

This commit fixes such issues by adding a kill flag that is raised when
calling AprsClien.disconnect() to the while conditions of both loops inside
AprsClient.run().

Note: the outermost loop could still remain a while True loop as the
exit condition is checked at the end of the loop body.
pull/26/head
Anze Kolar 2017-07-20 10:58:28 +02:00
rodzic d0044deb47
commit 182f9518a4
2 zmienionych plików z 8 dodań i 3 usunięć

Wyświetl plik

@ -19,6 +19,8 @@ class AprsClient:
self.aprs_user = aprs_user
self.aprs_filter = aprs_filter
self._kill = False
def connect(self):
# create socket, connect to server, login and make a file object associated with the socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -45,11 +47,13 @@ class AprsClient:
except OSError:
self.logger.error('Socket close error', exc_info=True)
self._kill = True
def run(self, callback, timed_callback=lambda client: None, autoreconnect=False):
while True:
while not self._kill:
try:
keepalive_time = time()
while True:
while not self._kill:
if time() - keepalive_time > settings.APRS_KEEPALIVE_TIME:
self.logger.info('Send keepalive')
self.sock.send('#keepalive\n'.encode())
@ -71,7 +75,7 @@ class AprsClient:
except socket.error:
self.logger.error('socket.error', exc_info=True)
if autoreconnect:
if autoreconnect and not self._kill:
self.connect()
else:
return

Wyświetl plik

@ -42,6 +42,7 @@ class OgnClientTest(unittest.TestCase):
client.disconnect()
client.sock.shutdown.assert_called_once_with(0)
client.sock.close.assert_called_once_with()
self.assertTrue(client._kill)
def test_50_live_messages(self):
print("Enter")