Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ashleysommer/sanic-synchro-ctx

Plugin to provide an App context that is shared across multiple workers
https://github.com/ashleysommer/sanic-synchro-ctx

Last synced: 16 days ago
JSON representation

Plugin to provide an App context that is shared across multiple workers

Awesome Lists containing this project

README

        

# Sanic-Synchro-Ctx
Plugin to provide an App context that is shared across multiple workers

Can use native python SyncManager backend, or Redis if you want. (Redis is much faster).

## Installation
```bash
$ pip3 install sanic-synchro-ctx
```

Or in a python virtualenv _(these example commandline instructions are for a Linux/Unix based OS)_
```bash
$ python3 -m virtualenv --python=python3 --no-site-packages .venv
$ source ./.venv/bin/activate
$ pip3 install sanic sanic-synchro-ctx
```

To exit the virtual enviornment:
```bash
$ deactivate
```

## Redis Extension
You can install the relevant Redis libraries for this plugin, with the installable redis extension:
```bash
$ pip3 install sanic-synchro-ctx[redis]
```
That is the same as running:
```bash
$ pip3 install "sanic-synchro-ctx" "aioredis>=2.0" "hiredis>=1.0"
```

## Compatibility
* Works with Python 3.8 and greater.
* Works with Sanic v21.9.0 and greater.
* If you are installing the redis library separately, use aioredis >= 2.0
* If you have sanic-ext installed, you must use Sanic-Synchro-CTX as an extension (see simple example below).

## Usage
A very simple example, it uses the native python SyncManager backend, doesn't require a Redis connection.
```python3
from sanic_synchro_ctx import SanicSynchroCtx
app = Sanic("sample")
s = SanicSynchroCtx(app)

@app.after_server_start
def handler(app, loop=None):
# This will only set this value if it doesn't already exist
# So only the first worker will set this value
app.ctx.synchro.set_default({"counter": 0})

@app.route("/inc")
def increment(request: Request):
# atomic increment operation
counter = request.app.ctx.synchro.increment("counter")
print("counter: {}".format(counter), flush=True)
return html("

Incremented!

")

@app.route("/count")
def increment(request: Request):
# Get from shared context:
counter = request.app.ctx.synchro.counter
print("counter: {}".format(counter), flush=True)
return html(f"

count: {counter}

")

app.run("127.0.0.1", port=8000, workers=8)
```

_Note: If you have Sanic-ext installed, you **must** use Sanic-Synchro-CTX in conjunction with Sanic-ext_

Sanic-ext example:
```python
from sanic_ext import Extend
from sanic_synchro_ctx import SanicSynchroCtx

app = Sanic("simple")
Extend(app, extensions=[SanicSynchroCtx])

@app.after_server_start
def handler(app, loop=None):
# This will only set this value if it doesn't already exist
# So only the first worker will set this value
app.ctx.synchro.set_default({"counter": 0})

@app.route("/")
def index(request: Request):
counter = request.app.ctx.synchro.increment("counter")

print("counter: {}".format(counter), flush=True)
return html("

Hello World

")

app.run("127.0.0.1", port=8000, workers=8)
```

Redis example:
```python3
from sanic_synchro_ctx import SanicSynchroCtx
redis = aioredis.from_url("redis://localhost")
app = Sanic("sample")
s = SanicSynchroCtx(app, backend="redis", redis_client=redis)

@app.after_server_start
async def handler(app, loop=None):
# This will only set this value if it doesn't already exist
# So only the first worker will set this value
await app.ctx.synchro.set_default({"counter": 0})

@app.route("/inc")
async def increment(request: Request):
# atomic increment operation
counter = await request.app.ctx.synchro.increment("counter")
print(f"counter: {counter}", flush=True)
return html("

Incremented!

")

@app.route("/count")
async def increment(request: Request):
# Get from shared context:
counter = await request.app.ctx.synchro.counter
print(f"counter: {counter}", flush=True)
return html(f"

count: {counter}

")

app.run("127.0.0.1", port=8000, workers=8)
```

## Changelog
A comprehensive changelog is kept in the [CHANGELOG file](https://github.com/ashleysommer/sanic-synchro-ctx/blob/master/CHANGELOG.md).

## Benchmarks
I've done some basic benchmarks. SyncManager works surprisingly well, but Redis backend is much faster.

## License
This repository is licensed under the MIT License. See the [LICENSE deed](https://github.com/ashleysommer/sanic-synchro-ctx/blob/master/LICENSE.txt) for details.