pyramid-forksafe


Namepyramid-forksafe JSON
Version 0.2.0 PyPI version JSON
download
home_pagehttps://github.com/jvanasco/pyramid_forksafe
SummaryStandardizes server `fork` events into Pyrmamid events
upload_time2023-06-13 21:02:27
maintainer
docs_urlNone
authorJonathan Vanasco
requires_python
licenseMIT
keywords web pyramid fork uwsgi nginx
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            pyramid_forksafe
================

Build Status: ![Python package](https://github.com/jvanasco/pyramid_forksafe/workflows/Python%20package/badge.svg)

This package creates standardized Pyramid events for various forking hooks in popular deployment containers.

Using `pyramid_forksafe` allows a developer to write generic routines for forking events, allowing them to easily swap containers during deployment or development.

Each event is invoked with the application's `registry`, through which one can access `registry.settings`

## Why?

Pyramid is Thread Safe, which is different than Fork Safe.

Several popular libraries are not fork-safe:

* SqlAlchemy's connection pool is not fork-safe.  Your deployment *must* call `engine.dispose()` after a fork.
* PyMongo's connections and locks are not fork-safe.  The entire client must be replaced after a fork.
* PyCrypto's Random generator will only work correctly if Random.atfork() is called.

In some situations, a developer may need to access the registry and/or settings during postfork actions. Getting this information into a custom hook can be a hassle, as one will need to write against each container's API instead of Pyramid's. 

This blog posting describes the difference between fork-safe and thread-safe pretty well  http://www.dctrwatson.com/2010/09/python-thread-safe-does-not-mean-fork-safe/


## Usage - Generic

Define a GENERIC hook.  

	from pyramid_forksafe.events import ApplicationPostFork

    def post_fork_hook(event):
    	"""
    	The event has an attribute for the Pyramid Application's `registry`
    		`event.registry`
    	""""
        cyrpto_atfork()
        models.engine.dispose()

    config.add_subscriber(post_fork_hook, ApplicationPostFork)

You can import the generic package in your `environment.ini` file (or main config), and this will try to enable services if possible:

	# development.ini
    pyramid.includes = pyramid_forksafe

or you may wish to import a SPECIFIC container package in your `environment.ini` file (or main config)

	# development.ini
    pyramid.includes = pyramid_forksafe.containers.uwsgi

Currently, this approach only works for `uWSGI`.  `gunicorn` requires another approach.


## Usage - uWSGI

simply include the package and uwsgi will be automatically enabled:

in your `__init__.py`:

    config.include('pyramid_forksafe')

or your `{environment}.ini`

    pyramid.includes = pyramid_forksafe

important note:

you MUST run uWSGI with the `--master` argument.


## Usage - gunicorn

`gunicorn` will need some hooks imported into it's python configuration file

assuming you invoke gunicorn like this:

	gunicorn --paste production.ini -c config.py

then your `config.py` just needs to import the container hooks:

    from pyramid_forksafe.containers.gunicorn import (
        pre_fork,
        post_fork,
        post_worker_init,
    )

those hooks are written to the `gunicorn` api, and will invoke the notification

you can also update the debug tool by running after configuration:

	from pyramid_forksafe.containers.gunicorn import mark_configured
	mark_configured(config.registry)


## Container Support

Currently `uwsgi` and `gunicorn` are supported with the hooks outlined below.   Celery integration is planned.  Pull requests are very welcome.


| container | pyramid\_forksafe event      | container hook |
|-----------|-----------------------------|------|
| uWSGI     | `ApplicationPostFork`       | [`postfork`](http://uwsgi-docs.readthedocs.io/en/latest/PythonDecorators.html#uwsgidecorators.postfork) |
| gunicorn  | `ApplicationPostFork`       | [`post_fork`](http://docs.gunicorn.org/en/latest/settings.html#post-fork) |
| gunicorn  | `ApplicationPreFork`        | [`pre_fork`](http://docs.gunicorn.org/en/latest/settings.html#pre-fork) |
| gunicorn  | `ApplicationPostWorkerInit` | [`post_worker_init`](http://docs.gunicorn.org/en/latest/settings.html#post-worker-init) |


## The Debug Object

including this package will put an informative dict into `registry.pyramid_forksafe`

under waitress, it will look like this:

	[('status', 'attempting auto-configure'),
	 ('environment', None),
	 ('autoconfigure.log', ['uWSGI not available']),
	 ('executed_hooks', set([]))]

under uWSGI without master, it will look like this:

	[('status', 'uWSGI error'),
	 ('environment', None),
	 ('autoconfigure.log',
	  ['uWSGI error: you have to enable the uWSGI master process to use this module']),
	 ('executed_hooks', set([]))]

under uWSGI properly configured, it will look like this:

	[('status', 'uWSGI hook configured'),
	 ('environment', 'uWSGI'),
	 ('autoconfigure.log', ['uWSGI available', 'uWSGI hook configured']),
	 ('executed_hooks',
	  set([('containers.uwsgi.post_fork_hook', 'ApplicationPostFork')]))]


## Debugtoolbar support

to enable the debugtoobar support, you can configure your `development.ini` with:

	debugtoolbar.includes = pyramid_forksafe.debugtoolbar

The toolbar just shows the debug object `request.registry.pyramid_forksafe` on the toolbar

This should always show an error, because the debugtoolbar does not run under forking servers.



## Status
2019.05.01 - debugtoolbar
2019.04.30 - debug object
2019.04.29 - Python3 Support. This has been production safe for uWSGI for a while now.
2016.11.09 - this is experimental

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/jvanasco/pyramid_forksafe",
    "name": "pyramid-forksafe",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "web pyramid fork uwsgi nginx",
    "author": "Jonathan Vanasco",
    "author_email": "jonathan@findmeon.com",
    "download_url": "https://files.pythonhosted.org/packages/a4/c1/191520d35efb8a7f5979e71704616f5ae53d007b9d790b9ebb87b02a286b/pyramid_forksafe-0.2.0.tar.gz",
    "platform": null,
    "description": "pyramid_forksafe\n================\n\nBuild Status: ![Python package](https://github.com/jvanasco/pyramid_forksafe/workflows/Python%20package/badge.svg)\n\nThis package creates standardized Pyramid events for various forking hooks in popular deployment containers.\n\nUsing `pyramid_forksafe` allows a developer to write generic routines for forking events, allowing them to easily swap containers during deployment or development.\n\nEach event is invoked with the application's `registry`, through which one can access `registry.settings`\n\n## Why?\n\nPyramid is Thread Safe, which is different than Fork Safe.\n\nSeveral popular libraries are not fork-safe:\n\n* SqlAlchemy's connection pool is not fork-safe.  Your deployment *must* call `engine.dispose()` after a fork.\n* PyMongo's connections and locks are not fork-safe.  The entire client must be replaced after a fork.\n* PyCrypto's Random generator will only work correctly if Random.atfork() is called.\n\nIn some situations, a developer may need to access the registry and/or settings during postfork actions. Getting this information into a custom hook can be a hassle, as one will need to write against each container's API instead of Pyramid's. \n\nThis blog posting describes the difference between fork-safe and thread-safe pretty well  http://www.dctrwatson.com/2010/09/python-thread-safe-does-not-mean-fork-safe/\n\n\n## Usage - Generic\n\nDefine a GENERIC hook.  \n\n\tfrom pyramid_forksafe.events import ApplicationPostFork\n\n    def post_fork_hook(event):\n    \t\"\"\"\n    \tThe event has an attribute for the Pyramid Application's `registry`\n    \t\t`event.registry`\n    \t\"\"\"\"\n        cyrpto_atfork()\n        models.engine.dispose()\n\n    config.add_subscriber(post_fork_hook, ApplicationPostFork)\n\nYou can import the generic package in your `environment.ini` file (or main config), and this will try to enable services if possible:\n\n\t# development.ini\n    pyramid.includes = pyramid_forksafe\n\nor you may wish to import a SPECIFIC container package in your `environment.ini` file (or main config)\n\n\t# development.ini\n    pyramid.includes = pyramid_forksafe.containers.uwsgi\n\nCurrently, this approach only works for `uWSGI`.  `gunicorn` requires another approach.\n\n\n## Usage - uWSGI\n\nsimply include the package and uwsgi will be automatically enabled:\n\nin your `__init__.py`:\n\n    config.include('pyramid_forksafe')\n\nor your `{environment}.ini`\n\n    pyramid.includes = pyramid_forksafe\n\nimportant note:\n\nyou MUST run uWSGI with the `--master` argument.\n\n\n## Usage - gunicorn\n\n`gunicorn` will need some hooks imported into it's python configuration file\n\nassuming you invoke gunicorn like this:\n\n\tgunicorn --paste production.ini -c config.py\n\nthen your `config.py` just needs to import the container hooks:\n\n    from pyramid_forksafe.containers.gunicorn import (\n        pre_fork,\n        post_fork,\n        post_worker_init,\n    )\n\nthose hooks are written to the `gunicorn` api, and will invoke the notification\n\nyou can also update the debug tool by running after configuration:\n\n\tfrom pyramid_forksafe.containers.gunicorn import mark_configured\n\tmark_configured(config.registry)\n\n\n## Container Support\n\nCurrently `uwsgi` and `gunicorn` are supported with the hooks outlined below.   Celery integration is planned.  Pull requests are very welcome.\n\n\n| container | pyramid\\_forksafe event      | container hook |\n|-----------|-----------------------------|------|\n| uWSGI     | `ApplicationPostFork`       | [`postfork`](http://uwsgi-docs.readthedocs.io/en/latest/PythonDecorators.html#uwsgidecorators.postfork) |\n| gunicorn  | `ApplicationPostFork`       | [`post_fork`](http://docs.gunicorn.org/en/latest/settings.html#post-fork) |\n| gunicorn  | `ApplicationPreFork`        | [`pre_fork`](http://docs.gunicorn.org/en/latest/settings.html#pre-fork) |\n| gunicorn  | `ApplicationPostWorkerInit` | [`post_worker_init`](http://docs.gunicorn.org/en/latest/settings.html#post-worker-init) |\n\n\n## The Debug Object\n\nincluding this package will put an informative dict into `registry.pyramid_forksafe`\n\nunder waitress, it will look like this:\n\n\t[('status', 'attempting auto-configure'),\n\t ('environment', None),\n\t ('autoconfigure.log', ['uWSGI not available']),\n\t ('executed_hooks', set([]))]\n\nunder uWSGI without master, it will look like this:\n\n\t[('status', 'uWSGI error'),\n\t ('environment', None),\n\t ('autoconfigure.log',\n\t  ['uWSGI error: you have to enable the uWSGI master process to use this module']),\n\t ('executed_hooks', set([]))]\n\nunder uWSGI properly configured, it will look like this:\n\n\t[('status', 'uWSGI hook configured'),\n\t ('environment', 'uWSGI'),\n\t ('autoconfigure.log', ['uWSGI available', 'uWSGI hook configured']),\n\t ('executed_hooks',\n\t  set([('containers.uwsgi.post_fork_hook', 'ApplicationPostFork')]))]\n\n\n## Debugtoolbar support\n\nto enable the debugtoobar support, you can configure your `development.ini` with:\n\n\tdebugtoolbar.includes = pyramid_forksafe.debugtoolbar\n\nThe toolbar just shows the debug object `request.registry.pyramid_forksafe` on the toolbar\n\nThis should always show an error, because the debugtoolbar does not run under forking servers.\n\n\n\n## Status\n2019.05.01 - debugtoolbar\n2019.04.30 - debug object\n2019.04.29 - Python3 Support. This has been production safe for uWSGI for a while now.\n2016.11.09 - this is experimental\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Standardizes server `fork` events into Pyrmamid events",
    "version": "0.2.0",
    "project_urls": {
        "Homepage": "https://github.com/jvanasco/pyramid_forksafe"
    },
    "split_keywords": [
        "web",
        "pyramid",
        "fork",
        "uwsgi",
        "nginx"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a4c1191520d35efb8a7f5979e71704616f5ae53d007b9d790b9ebb87b02a286b",
                "md5": "fdc82239dcea0984dfd0131dc7431286",
                "sha256": "1a378c03cd690fa687c0ec18116224c3315b254a17caff7486c63843576b5359"
            },
            "downloads": -1,
            "filename": "pyramid_forksafe-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "fdc82239dcea0984dfd0131dc7431286",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 12187,
            "upload_time": "2023-06-13T21:02:27",
            "upload_time_iso_8601": "2023-06-13T21:02:27.479799Z",
            "url": "https://files.pythonhosted.org/packages/a4/c1/191520d35efb8a7f5979e71704616f5ae53d007b9d790b9ebb87b02a286b/pyramid_forksafe-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-13 21:02:27",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "jvanasco",
    "github_project": "pyramid_forksafe",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "pyramid-forksafe"
}
        
Elapsed time: 0.10970s