daemon-application


Namedaemon-application JSON
Version 2.0.0 PyPI version JSON
download
home_page
SummaryA simple python package for creating daemon applications.
upload_time2023-09-11 02:32:36
maintainerZhao ZhiPeng
docs_urlNone
authorZhao ZhiPeng
requires_python>=2.7, !=3.2.0
licenseMIT
keywords daemon-application
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # daemon-application

## Description

A simple python package for creating daemon applications.

*Notice:*

- *Runs the application in daemon mode on Linux only. On Windows, the application runs in foreground model.*


## Install

```
pip install daemon-application
```

## Usage

### Example for raw APIs

```
import time
import threading
import signal
from daemon_application import daemon_start

stopflag = False

def main():
    def on_exit(*args, **kwargs):
        with open("backgroud.log", "a", encoding="utf-8") as fobj:
            print("process got exit signal...", file=fobj)
            print(args, file=fobj)
            print(kwargs, file=fobj)
        global stopflag
        stopflag = True
    signal.signal(signal.SIGTERM, on_exit)
    signal.signal(signal.SIGINT, on_exit)
    while not stopflag:
        time.sleep(1)
        print(time.time())

if __name__ == "__main__":
    print("start background application...")
    daemon_start(main, "background.pid", True)
```

### Example for DaemonApplication

```
import time
from daemon_application import DaemonApplication

class HelloApplication(DaemonApplication):
    def main(self):
        while True:
            print("hello")
            time.sleep(1)

controller = HelloApplication().get_controller()

if __name__ == "__main__":
    controller()

```

### Example for DaemonApplication adding new global options

```
import time
import click
from daemon_application import DaemonApplication

class HelloApplication(DaemonApplication):

    def get_main_options(self):
        options = [
            click.option("-m", "--message", default="hello")
        ]
        return options + super().get_main_options()

    def main(self):
        while True:
            print(self.config["message"])
            time.sleep(1)

controller = HelloApplication().get_controller()

if __name__ == "__main__":
    controller()
```

*The output of the command help that added a new global option*

```
Usage: example.py [OPTIONS] COMMAND [ARGS]...

Options:
  --pidfile TEXT          pidfile file path.
  --workspace TEXT        Set running folder
  --daemon / --no-daemon  Run application in background or in foreground.
  -c, --config TEXT       Config file path. Application will search config
                          file if this option is missing. Use sub-command
                          show-config-fileapaths to get the searching tactics.

  -m, --message TEXT
  --help                  Show this message and exit.

Commands:
  restart                Restart Daemon application.
  show-config-filepaths  Print out the config searching paths.
  start                  Start daemon application.
  stop                   Stop daemon application.
```

### Example of graceful-stop-application using daemon-application and graceful-sigterm.

```python
import time
import signal
import logging
import sigterm # pip install graceful-sigterm
from daemon_application import DaemonApplication

_logger = logging.getLogger(__name__)


class HelloApplication(DaemonApplication):
    def main(self):
        # setup sigterm
        sigterm.setup()
        sigterm.setup(signal.SIGINT)
        sigterm.register_worker(self._main)
        sigterm.execute()

    def _main(self):
        # start application main
        while not sigterm.is_stopped():
            _logger.info("hello")
            time.sleep(1)
        _logger.info("gracefully stopped!")


controller = HelloApplication().get_controller()

if __name__ == "__main__":
    controller()
```

Start the application, and kill by the pid. The application output looks like:

```log
test@test daemon-application % python t1.py --no-daemon start
Start application without config file.
2023-09-11 10:13:44,186 INFO 7634 8205548160base daemon_start 174 Start application in FRONT mode, pid=7634.
2023-09-11 10:13:44,187 INFO 7634 8205548160sigterm setup 88 signal setup: sig=15, handler=<function default_handler at 0x100beaa20>
2023-09-11 10:13:44,187 INFO 7634 8205548160sigterm setup 88 signal setup: sig=2, handler=<function default_handler at 0x100beaa20>
2023-09-11 10:13:44,187 INFO 7634 8205548160sigterm execute 94 start workers...
2023-09-11 10:13:44,187 INFO 7634 6180237312t1 _main 19 hello
2023-09-11 10:13:45,192 INFO 7634 6180237312t1 _main 19 hello
2023-09-11 10:13:46,197 INFO 7634 6180237312t1 _main 19 hello
2023-09-11 10:13:47,202 INFO 7634 6180237312t1 _main 19 hello
2023-09-11 10:13:48,208 INFO 7634 6180237312t1 _main 19 hello
2023-09-11 10:13:49,214 INFO 7634 6180237312t1 _main 19 hello
2023-09-11 10:13:50,219 INFO 7634 6180237312t1 _main 19 hello
2023-09-11 10:13:50,404 INFO 7634 8205548160sigterm default_handler 51 get TERM signal, prepare to stop server...
2023-09-11 10:13:51,224 INFO 7634 6180237312t1 _main 21 gracefully stopped!
2023-09-11 10:13:51,225 INFO 7634 8205548160sigterm execute 101 worker <Thread(Thread-1 (_main), stopped daemon 6180237312)> end.
2023-09-11 10:13:51,225 INFO 7634 8205548160sigterm execute 104 main thread end.
```

Look into the log, you will see `gracefully stopped!`. The kill command is not kill the main process, but set the is_stopped flag, and the application gracefully exit by it's logical controller.

## Configs

### Config items and default values

- pidfile: app.pid
- stop-timeout: 30
- stop-signal: SIGINT
- daemon: True
- workspace: ""
- loglevel: INFO
- logfile: app.log
- logfmt: default

### services fields

- class: class path string, e.g. zenutils.serviceutils.DebugService
- args: []
- kwargs: {}

## Note

Logging is ENABLED as `logutils.setup(**self.config)` by default.

## Test Passed With Pythons

- 2.7
- 3.3
- 3.4
- 3.5
- 3.6
- 3.7
- 3.8
- 3.9
- 3.10
- 3.11

## Release

### v2.0.0

- Remove rpc related parts. *Notice:* SimpleRpcApplication Based Application should change deps to `daemon-application~=1.0.5`.

### v1.0.5

- Change rpcutils, make it more easy to use.

### v0.5.10

- Use dictutils.deep_merge to update config.

### v0.5.9

- Unit test passed.

### v0.5.8

- Work with zenutils.socketserverutils.

### v0.5.7

- Improve the srpcd command.

### v0.5.6

- Add SimpleRpcServer class and srpcd command.

### v0.5.5

- Config in DaemonApplication is set to the dictutils.Object class for ease use while remaining compatible with all dict operations.

### v0.5.4

- Doc update.

### v0.5.3

- Add DaemonApplication.load_config, so that you can start DaemonApplication service directly by your code.
- Add stop_timeout for daemon_stop. If stop timeout, kill process tree by force.

### v0.5.2

- Add global options: loglevel, logfile, logfmt.
- Update default_config override mechanism.

### v0.4.4

- Fix the problem in sub-command stop.

### v0.4.3

- Deps on pyyaml.

### v0.4.2

- Remove a print() statement.

### v0.4.1

- Fix documents URLs.

### v0.4.0

- Remove fastutils deps.
- Add `--config` global command option for DaemonApplication.
- Provide a way to override the global options for subclass of DaemonApplication.
- The sub-command `restart` will do just `start` if the old application is not running or crashed.
- Use gitee.com source code hosting service.

### v0.3.3

- Fix show-config-filepaths.

### v0.3.2

- Add click deps in requirements.txt

### v0.3.1

- Add DaemonApplication.

### v0.3.0

- New wrapper.

### v0.2.1

- Old releases.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "daemon-application",
    "maintainer": "Zhao ZhiPeng",
    "docs_url": null,
    "requires_python": ">=2.7, !=3.2.0",
    "maintainer_email": "zhaozhipeng@zencore.cn",
    "keywords": "daemon-application",
    "author": "Zhao ZhiPeng",
    "author_email": "zhaozhipeng@zencore.cn",
    "download_url": "https://files.pythonhosted.org/packages/18/e1/25d87de141dfc2a0b6f4f24307579bcb39ef93551b231f7f9172120bdb37/daemon-application-2.0.0.tar.gz",
    "platform": null,
    "description": "# daemon-application\n\n## Description\n\nA simple python package for creating daemon applications.\n\n*Notice:*\n\n- *Runs the application in daemon mode on Linux only. On Windows, the application runs in foreground model.*\n\n\n## Install\n\n```\npip install daemon-application\n```\n\n## Usage\n\n### Example for raw APIs\n\n```\nimport time\nimport threading\nimport signal\nfrom daemon_application import daemon_start\n\nstopflag = False\n\ndef main():\n    def on_exit(*args, **kwargs):\n        with open(\"backgroud.log\", \"a\", encoding=\"utf-8\") as fobj:\n            print(\"process got exit signal...\", file=fobj)\n            print(args, file=fobj)\n            print(kwargs, file=fobj)\n        global stopflag\n        stopflag = True\n    signal.signal(signal.SIGTERM, on_exit)\n    signal.signal(signal.SIGINT, on_exit)\n    while not stopflag:\n        time.sleep(1)\n        print(time.time())\n\nif __name__ == \"__main__\":\n    print(\"start background application...\")\n    daemon_start(main, \"background.pid\", True)\n```\n\n### Example for DaemonApplication\n\n```\nimport time\nfrom daemon_application import DaemonApplication\n\nclass HelloApplication(DaemonApplication):\n    def main(self):\n        while True:\n            print(\"hello\")\n            time.sleep(1)\n\ncontroller = HelloApplication().get_controller()\n\nif __name__ == \"__main__\":\n    controller()\n\n```\n\n### Example for DaemonApplication adding new global options\n\n```\nimport time\nimport click\nfrom daemon_application import DaemonApplication\n\nclass HelloApplication(DaemonApplication):\n\n    def get_main_options(self):\n        options = [\n            click.option(\"-m\", \"--message\", default=\"hello\")\n        ]\n        return options + super().get_main_options()\n\n    def main(self):\n        while True:\n            print(self.config[\"message\"])\n            time.sleep(1)\n\ncontroller = HelloApplication().get_controller()\n\nif __name__ == \"__main__\":\n    controller()\n```\n\n*The output of the command help that added a new global option*\n\n```\nUsage: example.py [OPTIONS] COMMAND [ARGS]...\n\nOptions:\n  --pidfile TEXT          pidfile file path.\n  --workspace TEXT        Set running folder\n  --daemon / --no-daemon  Run application in background or in foreground.\n  -c, --config TEXT       Config file path. Application will search config\n                          file if this option is missing. Use sub-command\n                          show-config-fileapaths to get the searching tactics.\n\n  -m, --message TEXT\n  --help                  Show this message and exit.\n\nCommands:\n  restart                Restart Daemon application.\n  show-config-filepaths  Print out the config searching paths.\n  start                  Start daemon application.\n  stop                   Stop daemon application.\n```\n\n### Example of graceful-stop-application using daemon-application and graceful-sigterm.\n\n```python\nimport time\nimport signal\nimport logging\nimport sigterm # pip install graceful-sigterm\nfrom daemon_application import DaemonApplication\n\n_logger = logging.getLogger(__name__)\n\n\nclass HelloApplication(DaemonApplication):\n    def main(self):\n        # setup sigterm\n        sigterm.setup()\n        sigterm.setup(signal.SIGINT)\n        sigterm.register_worker(self._main)\n        sigterm.execute()\n\n    def _main(self):\n        # start application main\n        while not sigterm.is_stopped():\n            _logger.info(\"hello\")\n            time.sleep(1)\n        _logger.info(\"gracefully stopped!\")\n\n\ncontroller = HelloApplication().get_controller()\n\nif __name__ == \"__main__\":\n    controller()\n```\n\nStart the application, and kill by the pid. The application output looks like:\n\n```log\ntest@test daemon-application % python t1.py --no-daemon start\nStart application without config file.\n2023-09-11 10:13:44,186 INFO 7634 8205548160base daemon_start 174 Start application in FRONT mode, pid=7634.\n2023-09-11 10:13:44,187 INFO 7634 8205548160sigterm setup 88 signal setup: sig=15, handler=<function default_handler at 0x100beaa20>\n2023-09-11 10:13:44,187 INFO 7634 8205548160sigterm setup 88 signal setup: sig=2, handler=<function default_handler at 0x100beaa20>\n2023-09-11 10:13:44,187 INFO 7634 8205548160sigterm execute 94 start workers...\n2023-09-11 10:13:44,187 INFO 7634 6180237312t1 _main 19 hello\n2023-09-11 10:13:45,192 INFO 7634 6180237312t1 _main 19 hello\n2023-09-11 10:13:46,197 INFO 7634 6180237312t1 _main 19 hello\n2023-09-11 10:13:47,202 INFO 7634 6180237312t1 _main 19 hello\n2023-09-11 10:13:48,208 INFO 7634 6180237312t1 _main 19 hello\n2023-09-11 10:13:49,214 INFO 7634 6180237312t1 _main 19 hello\n2023-09-11 10:13:50,219 INFO 7634 6180237312t1 _main 19 hello\n2023-09-11 10:13:50,404 INFO 7634 8205548160sigterm default_handler 51 get TERM signal, prepare to stop server...\n2023-09-11 10:13:51,224 INFO 7634 6180237312t1 _main 21 gracefully stopped!\n2023-09-11 10:13:51,225 INFO 7634 8205548160sigterm execute 101 worker <Thread(Thread-1 (_main), stopped daemon 6180237312)> end.\n2023-09-11 10:13:51,225 INFO 7634 8205548160sigterm execute 104 main thread end.\n```\n\nLook into the log, you will see `gracefully stopped!`. The kill command is not kill the main process, but set the is_stopped flag, and the application gracefully exit by it's logical controller.\n\n## Configs\n\n### Config items and default values\n\n- pidfile: app.pid\n- stop-timeout: 30\n- stop-signal: SIGINT\n- daemon: True\n- workspace: \"\"\n- loglevel: INFO\n- logfile: app.log\n- logfmt: default\n\n### services fields\n\n- class: class path string, e.g. zenutils.serviceutils.DebugService\n- args: []\n- kwargs: {}\n\n## Note\n\nLogging is ENABLED as `logutils.setup(**self.config)` by default.\n\n## Test Passed With Pythons\n\n- 2.7\n- 3.3\n- 3.4\n- 3.5\n- 3.6\n- 3.7\n- 3.8\n- 3.9\n- 3.10\n- 3.11\n\n## Release\n\n### v2.0.0\n\n- Remove rpc related parts. *Notice:* SimpleRpcApplication Based Application should change deps to `daemon-application~=1.0.5`.\n\n### v1.0.5\n\n- Change rpcutils, make it more easy to use.\n\n### v0.5.10\n\n- Use dictutils.deep_merge to update config.\n\n### v0.5.9\n\n- Unit test passed.\n\n### v0.5.8\n\n- Work with zenutils.socketserverutils.\n\n### v0.5.7\n\n- Improve the srpcd command.\n\n### v0.5.6\n\n- Add SimpleRpcServer class and srpcd command.\n\n### v0.5.5\n\n- Config in DaemonApplication is set to the dictutils.Object class for ease use while remaining compatible with all dict operations.\n\n### v0.5.4\n\n- Doc update.\n\n### v0.5.3\n\n- Add DaemonApplication.load_config, so that you can start DaemonApplication service directly by your code.\n- Add stop_timeout for daemon_stop. If stop timeout, kill process tree by force.\n\n### v0.5.2\n\n- Add global options: loglevel, logfile, logfmt.\n- Update default_config override mechanism.\n\n### v0.4.4\n\n- Fix the problem in sub-command stop.\n\n### v0.4.3\n\n- Deps on pyyaml.\n\n### v0.4.2\n\n- Remove a print() statement.\n\n### v0.4.1\n\n- Fix documents URLs.\n\n### v0.4.0\n\n- Remove fastutils deps.\n- Add `--config` global command option for DaemonApplication.\n- Provide a way to override the global options for subclass of DaemonApplication.\n- The sub-command `restart` will do just `start` if the old application is not running or crashed.\n- Use gitee.com source code hosting service.\n\n### v0.3.3\n\n- Fix show-config-filepaths.\n\n### v0.3.2\n\n- Add click deps in requirements.txt\n\n### v0.3.1\n\n- Add DaemonApplication.\n\n### v0.3.0\n\n- New wrapper.\n\n### v0.2.1\n\n- Old releases.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A simple python package for creating daemon applications.",
    "version": "2.0.0",
    "project_urls": null,
    "split_keywords": [
        "daemon-application"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d778b223b825f742a75b4897f86f085d96a4f5ccdb45bd75077505f922da9615",
                "md5": "335cd26e7eb48fd7cec37839a4365cce",
                "sha256": "aa5adf2d3ddc43dbfb31a9ebc03e69fb4e99fe894a69c9f1dbca0d4442e67ace"
            },
            "downloads": -1,
            "filename": "daemon_application-2.0.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "335cd26e7eb48fd7cec37839a4365cce",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=2.7, !=3.2.0",
            "size": 9496,
            "upload_time": "2023-09-11T02:32:34",
            "upload_time_iso_8601": "2023-09-11T02:32:34.332226Z",
            "url": "https://files.pythonhosted.org/packages/d7/78/b223b825f742a75b4897f86f085d96a4f5ccdb45bd75077505f922da9615/daemon_application-2.0.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "18e125d87de141dfc2a0b6f4f24307579bcb39ef93551b231f7f9172120bdb37",
                "md5": "50c7e444c034d534b3d59a329c72f503",
                "sha256": "3da3f0e78c7e073aa60c341a542a68641093b78e340d7d2bdb1fa4f813c867af"
            },
            "downloads": -1,
            "filename": "daemon-application-2.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "50c7e444c034d534b3d59a329c72f503",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=2.7, !=3.2.0",
            "size": 11122,
            "upload_time": "2023-09-11T02:32:36",
            "upload_time_iso_8601": "2023-09-11T02:32:36.350539Z",
            "url": "https://files.pythonhosted.org/packages/18/e1/25d87de141dfc2a0b6f4f24307579bcb39ef93551b231f7f9172120bdb37/daemon-application-2.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-09-11 02:32:36",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "daemon-application"
}
        
Elapsed time: 0.12924s