Daemon does not start
YuriyLisovskiy opened this issue · 3 comments
I've written some code to test the service class:
import time
from service import Service
class TestService(Service):
def run(self):
i = 0
while i < 5 and not self.got_sigterm():
i += 1
with open('./file.txt', 'a') as the_file:
the_file.write('Service info: {}\n'.format(i))
time.sleep(1)
if __name__ == '__main__':
service = TestService('test_service', '/tmp')
service.start()
time.sleep(1)
print(service.get_pid())
The program printed out None
and file was not created.
After I've tried to modify the module, so this:
service/src/service/__init__.py
Lines 420 to 450 in 5cfe2aa
I have changed to this:
try:
setproctitle.setproctitle(self.name)
self._debug('Process title has been set')
files_preserve = (self.files_preserve +
self._get_logger_file_handles())
DaemonContext(
detach_process=False,
signal_map={
signal.SIGTTIN: None,
signal.SIGTTOU: None,
signal.SIGTSTP: None,
signal.SIGTERM: on_sigterm,
},
files_preserve=files_preserve)
self._debug('Daemon context has been established')
# Python's signal handling mechanism only forwards signals to
# the main thread and only when that thread is doing something
# (e.g. not when it's waiting for a lock, etc.). If we use the
# main thread for the ``run`` method this means that we cannot
# use the synchronization devices from ``threading`` for
# communicating the reception of SIGTERM to ``run``. Hence we
# use a separate thread for ``run`` and make sure that the
# main loop receives signals. See
# https://bugs.python.org/issue1167930
thread = threading.Thread(target=runner)
thread.start()
while thread.is_alive():
time.sleep(1)
except Exception as e:
self.logger.exception(e)
i.e. removed with
near the DaemonContext
, line 425. And now service is running fine.
Why it is not working without this modification?
Is my test service is written incorrectly?
I am getting the same error. +1 to follow the issue.
@YuriyLisovskiy There are two issues with your code:
The first thing is that in the service process, the working directory is set to /
(the root directory). Unless your service is running as the root
user, you won't have the permission to create a file there. You can see that if you enable logging:
import logging
from logging.handlers import SysLogHandler
import os
import time
from service import find_syslog, Service
class TestService(Service):
def __init__(self, *args, **kwargs):
super(TestService, self).__init__(*args, **kwargs)
self.logger.addHandler(SysLogHandler(address=find_syslog(),
facility=SysLogHandler.LOG_DAEMON))
self.logger.setLevel(logging.INFO)
def run(self):
self.logger.info('cwd = {}'.format(os.getcwd()))
i = 0
while i < 5 and not self.got_sigterm():
i += 1
with open('./file.txt', 'a') as the_file:
the_file.write('Service info: {}\n'.format(i))
time.sleep(1)
With this code, I find the following in my /var/log/syslog
(that location might be different for you depending on your system's configuration):
Apr 27 14:55:24 leibniz cwd = /
Apr 27 14:55:24 leibniz [Errno 13] Permission denied: './file.txt'#012Traceback (most recent call last):#012 File "/home/torf/projects/service/src/service/__init__.py", line 407, in runner#012 self.run()#012 File "./issue11.py", line 26, in run#012 with open('./file.txt', 'a') as the_file:#012IOError: [Errno 13] Permission denied: './file.txt'
If you simply want to write into the current working directory of your script, then store that path in a variable (script_cwd = os.getcwd()
) and reference it from within run
-- or pass the directory to your service as a constructor argument.
The second issue is about service.get_pid()
returning None
. This could have two reasons: either your service isn't fully running when you call service.get_pid()
(it usually takes some seconds) or it has already exited because of the permission exception described above. An easy way to resolve the former problem is to pass block=True
to start
. That way, start
will block until the service is really running:
test_service = TestService('test_service', '/tmp')
test_service.start(block=True)
print(test_service.get_pid())
Regarding the fix you proposed: your changes completely disable the forking of the service into a separate process. That fixes the permission problem, but for the wrong reason 😉
I think this will fix your issues, so I'm closing this ticket. Feel free to reopen it if required.
@torfsen Thanks much =)