telepot icon indicating copy to clipboard operation
telepot copied to clipboard

Unable to terminate MessageLoop gracefully

Open bablokb opened this issue 7 years ago • 11 comments

The current MessageLoop implementation does not allow graceful termination of the message loop. Of course I could kill the process from the os-side, but I want to save state after termination of my bot. Also I think that it is good style to enable a clean shutdown of every program.

I had a look at your code and I think there is not a lot to do to make it work:

  • add an additional parameter stopEvent of type threading.Event to MessageLoop
  • pass this stopEvent to all threads
  • in the threads replace your while 1 - loops with while not stopEvent.wait(timeout)

Ok, that's the theory, in practice there is a little bit more work. You would have to make the parameter optional to keep compatibility and create your own threadEvent instance if the parameter is not passed. And you would probably also have to replace all daemon-threads with normal threads.

Now a supervisor thread could just call stopEvent.set() to terminate the MessageLoop (and all threads created by it), save state and do resource cleanup.

Bernhard

bablokb avatar Jul 14 '17 08:07 bablokb

For something that acts like a server, e.g. MessageLoop, I don't think it's necessary to provide a way to stop it from within the library. I think having the ability to stop it from the OS/process level is sufficient. If you want to clean up, the package atexit is perfect for this purpose (reference pull request #262), or you may do it by catching the SIGTERM signal (reference the signal package).

nickoala avatar Jul 16 '17 09:07 nickoala

This is a library and you can't make assumptions regarding the application. If I have a an application with integrated bot, and the user wants to closes it, should I pop up a message saying: "please open a shell, list all processes, grep for the correct pid and kill the process of the application!"?

I think it is a design flaw if a library does not care about cleaning up it's resources. And as I pointed out, fixing this flaw is not a major issue in telepot.

Fixing the problem might not be of high priority, but just neglecting seems a bit strange. But you might want to solve the problem together with migrating from threading to multiprocessing anyhow.

bablokb avatar Jul 19 '17 18:07 bablokb

I opened a PR to resolve this issue, see #267. With the reference to the task, one can cancel the task without closing the application.

das7pad avatar Jul 19 '17 20:07 das7pad

@bablokb, I get your point. I never envision an "integrated bot" within another application. But it is possible. I will put the cancelling capability on my todo list. Just can't guarantee when I can make it. Telepot is somewhat low-priority at this moment of my life.

@das7pad, I assume that #267 has been superseded by #268. I prefer to give the same capability to traditional and async version at the same time. I will accept your PR at some later time. Thank you.

nickoala avatar Jul 20 '17 09:07 nickoala

Oops, I mixed up. Thanks @aragaer for PR #268.

nickoala avatar Jul 20 '17 09:07 nickoala

Hi guys, please show me how i can stop message loop. If my wifi go down, Pycharm write me a lot of exception. I have a thread that use telegram bot and messageLoop to receive new command, but how i can stop the listener ? What's the code to do that ? Thanks a lot to all

markolino85 avatar Nov 20 '17 19:11 markolino85

Just call messageLoop.cancel()

aragaer avatar Nov 20 '17 20:11 aragaer

@aragaer The synced version does not have this method.

das7pad avatar Nov 20 '17 20:11 das7pad

bot.messageLoop.cancel() AttributeError: 'Bot' object has no attribute 'messageLoop'

markolino85 avatar Nov 20 '17 21:11 markolino85

You must use the MessageLoop that you started previously. But as you wrote that you are using separate threads, I assume that you imported telepot.loop and used telepot.loop.MessageLoop... - which does not have this functionallity anyways.

das7pad avatar Nov 20 '17 23:11 das7pad

@bablokb A solution to

"please open a shell, list all processes, grep for the correct pid and kill the process of the application!"

if command == '/exit':
        telegram_bot.sendMessage(chat_id, "Bot kill")
        time.sleep(1)
        os.kill(os.getpid(), signal.SIGKILL)

It's not clean but it works !

mire22 avatar Jan 28 '18 18:01 mire22