0

I've created a python3 script that runs fine on command line but when I try to run as a daemon in MacosX gives error 'EOFError: EOF when reading a line'. Basically code is as follows:

  (...)

  def main():

    # Connect
    port, speed = connect_port()

    device = XBeeDevice(port, speed)

    try:
      device.open()
      # print("Waiting for data...\n")

     (...)

      device.add_packet_received_callback(packet_received_callback)
      input()

    finally:
      if device is not None and device.is_open():
        device.close()

  if __name__ == '__main__':
    main()

plist seems to be fine as script starts and runs once before to give error:

Traceback (most recent call last):
File "/maslestorres.cat/jardiNet_datalogger.py", line 214, in <module>
main()
File "/maslestorres.cat/jardiNet_datalogger.py", line 206, in main
input()
EOFError: EOF when reading a line

So basically I don't know how to adapt the input() line to allow to run as a daemon. Python is version 3.7.2 and MacOSX is 10.8.5.

joanba
  • 281
  • 2
  • 15
  • Please explain what you’re doing in more detail. What is the purpose of `input()` in your code? Does it wait for the user’s approval to resume operation? Typically the whole point of a daemon is to run continuously without user interaction. – Vasiliy Faronov Mar 22 '19 at 14:03
  • input() function is just to ensure main never ends and callbacks are executed. Similar behavior can be obtained with a busy wait loop --> while True: pass but obviously this loop wastes CPU – joanba Mar 22 '19 at 14:30
  • Do I understand correctly that you want your daemon to `device.open()` once and then wait for packets indefinitely, running `packet_received_callback` on each one? – Vasiliy Faronov Mar 22 '19 at 14:37

1 Answers1

2

By its very nature, a daemon cannot input() from the console. You need another way to suspend the main thread indefinitely while letting the XBee PacketListener thread to keep running callbacks.

The easiest way to accomplish this would be to replace input() with:

while True:
    time.sleep(1000000)    # arbitrarily large number

When it’s time to shut down, your system’s service manager will stop your daemon:

  • either by sending SIGTERM — in which case your daemon will terminate immediately, without executing the finally block;
  • or by sending SIGINT — in which case a KeyboardInterrupt exception will bubble out of time.sleep(1000000), and the finally block will run.

In either case, your process should stop quickly.

For a more correct solution, capable also of handling SIGTERM gracefully, see here: https://stackoverflow.com/a/46346184/200445

Vasiliy Faronov
  • 11,840
  • 2
  • 38
  • 49