facet

Service manager for asyncio

https://github.com/pohmelie/facet

Science Score: 13.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
  • DOI references
  • Academic publication links
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (10.1%) to scientific vocabulary
Last synced: 11 months ago · JSON representation

Repository

Service manager for asyncio

Basic Info
  • Host: GitHub
  • Owner: pohmelie
  • License: mit
  • Language: Python
  • Default Branch: master
  • Size: 58.6 KB
Statistics
  • Stars: 17
  • Watchers: 1
  • Forks: 1
  • Open Issues: 0
  • Releases: 0
Created over 6 years ago · Last pushed over 2 years ago
Metadata Files
Readme Changelog License

readme.md

Facet

Service manager for asyncio (and classic blocking code since version 0.10.0).

Github actions status for master branch Codecov coverage for master branch Pypi version Pypi downloads count

Reasons

Asyncio

mode tries to do too much job: - Messy callbacks (on_start, on_started, on_crashed, etc.). - Inheritance restrict naming and forces super() calls. - Forced logging module and logging configuration.

Blocking code

  • ExitStack is too low-level to manage services.
  • Common api for async and blocking worlds.

Features

  • Simple (start, stop, dependencies and add_task).
  • Configurable via inheritance (graceful shutdown timeout).
  • Mixin (no super() required).
  • Requires no runner engine (Worker, Runner, etc.) just plain await or async with/with.

License

facet is offered under MIT license.

Requirements

  • python 3.11+

Last version with python 3.6+ support is 0.9.1

Usage

Asyncio

``` python import asyncio from facet import AsyncioServiceMixin

class B(AsyncioServiceMixin): def init(self): self.value = 0

async def start(self):
    self.value += 1
    print("b started")

async def stop(self):
    self.value -= 1
    print("b stopped")

class A(AsyncioServiceMixin): def init(self): self.b = B()

@property
def dependencies(self):
    return [self.b]

async def start(self):
    print("a started")

async def stop(self):
    print("a stopped")

asyncio.run(A().run()) This will produce: b started a started `` Start and stop order determined by strict rule: **dependencies must be started first and stopped last**. That is whyBstarts beforeA. SinceAmay useBinstart` routine.

Hit ctrl-c and you will see: a stopped b stopped Traceback (most recent call last): ... KeyboardInterrupt Stop order is reversed, since A may use B in stop routine. Any raised exception propagates to upper context. facet do not trying to be too smart.

Service can be used as a context manager. Instead of python asyncio.run(A().run()) Code can look like: ``` python async def main(): async with A() as a: assert a.b.value == 1 await a.wait()

asyncio.run(main()) ```

Another service feature is add_task method: ``` python class A(AsyncioServiceMixin): async def task(self): await asyncio.sleep(1) print("task done")

async def start(self):
    self.add_task(self.task())
    print("start done")

asyncio.run(A().run()) This will lead to background task creation and handling: start done task done ``` Any non-handled exception on background task will lead the whole service stack crashed. This is also a key feature to fall down fast and loud.

All background tasks will be cancelled and awaited on service stop.

You can manage dependencies start/stop to start sequently, parallel or mixed. Like this: ``` python class A(AsyncioServiceMixin): def init(self): self.b = B() self.c = C() self.d = D()

@property
def dependencies(self):
    return [
        [self.b, self.c],
        self.d,
    ]

`` This leads to firstbandcstarts parallel, after they successfully starteddwill try to start, and thenaitself start will be called. And on stop routineastop called first, thendstop, then bothbandc` stops parallel.

The rule here is first nesting level is sequential, second nesting level is parallel

Blocking code

Since version 0.10.0 facet can be used in blocking code with pretty same rules. But with limited API. For example: ``` python from facet import BlockingServiceMixin

class B(BlockingServiceMixin): def init(self): self.value = 0

def start(self):
    self.value += 1
    print("b started")

def stop(self):
    self.value -= 1
    print("b stopped")

class A(BlockingServiceMixin): def init(self): self.b = B()

@property
def dependencies(self):
    return [self.b]

def start(self):
    print("a started")

def stop(self):
    print("a stopped")

with A() as a: assert a.b.value == 1 This will produce: b started a started a stopped b stopped `` As you can see, there is nowaitmethod. Waiting and background tasks are on user shoulders and technically can be implemented withconcurrent.futuresmodule. Butfacetdo not provide such functionality, since there are a lot of ways to do it:threading/multiprocessing` and their primitives.

Also, there are no «sequential, parallel and mixed starts/stops for dependencies» feature. So, just put dependencies in dependencies property as a plain list and they will be started/stopped sequentially.

API

Asyncio

Here is public methods you get on inheritance/mixin:

start

python async def start(self): pass Start routine.

stop

python async def stop(self): pass Stop routine.

dependencies

python @property def dependencies(self) -> list[AsyncioServiceMixin | list[AsyncioServiceMixin]]: return [] Should return iterable of current service dependencies instances.

add_task

python def add_task(self, coroutine: Coroutine[Any, Any, Any]) -> asyncio.Task[Any]: Add background task.

run

python async def run(self) -> None: Run service and wait until it stop.

wait

python async def wait(self) -> None: Wait for service stop. Service must be started. This is useful when you use service as a context manager.

graceful_shutdown_timeout

python @property def graceful_shutdown_timeout(self) -> int: return 10 How much total time in seconds wait for stop routines. This property can be overriden with subclass: python class CustomServiceMixin(AsyncioServiceMixin): @property def graceful_shutdown_timeout(self): return 60

running

python @property def running(self) -> bool: Check if service is running

Blocking code

start

python def start(self): pass Start routine.

stop

python def stop(self): pass Stop routine.

dependencies

python @property def dependencies(self) -> list[BlockingServiceMixin | list[BlockingServiceMixin]]: return [] Should return iterable of current service dependencies instances.

running

python @property def running(self) -> bool: Check if service is running

Owner

  • Name: Nikita Melentev
  • Login: pohmelie
  • Kind: user
  • Location: Tbilisi, Georgia

GitHub Events

Total
  • Watch event: 4
Last Year
  • Watch event: 4

Committers

Last synced: almost 3 years ago

All Time
  • Total Commits: 32
  • Total Committers: 4
  • Avg Commits per committer: 8.0
  • Development Distribution Score (DDS): 0.375
Past Year
  • Commits: 0
  • Committers: 0
  • Avg Commits per committer: 0.0
  • Development Distribution Score (DDS): 0.0
Top Committers
Name Email Commits
pohmelie m****y@g****m 20
Nikita Melentev n****v@k****u 7
Sergey b****z@g****m 4
Nikita Melentev N****v@k****u 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: about 1 year ago

All Time
  • Total issues: 3
  • Total pull requests: 4
  • Average time to close issues: about 1 month
  • Average time to close pull requests: 3 days
  • Total issue authors: 2
  • Total pull request authors: 1
  • Average comments per issue: 3.33
  • Average comments per pull request: 2.0
  • Merged pull requests: 4
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 0
  • Pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 0
  • Average comments per issue: 0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • pohmelie (2)
  • Vasiliy566 (1)
Pull Request Authors
  • bizywizy (4)
Top Labels
Issue Labels
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads:
    • pypi 5,071 last-month
  • Total dependent packages: 1
  • Total dependent repositories: 2
  • Total versions: 12
  • Total maintainers: 1
pypi.org: facet

service manager for asyncio

  • Documentation: https://github.com/pohmelie/facet
  • License: MIT License Copyright (c) 2019 Nikita Melentev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  • Latest release: 0.10.1
    published over 2 years ago
  • Versions: 12
  • Dependent Packages: 1
  • Dependent Repositories: 2
  • Downloads: 5,071 Last month
Rankings
Dependent packages count: 4.7%
Downloads: 9.0%
Dependent repos count: 11.6%
Average: 13.1%
Stargazers count: 17.7%
Forks count: 22.6%
Maintainers (1)
Last synced: 12 months ago

Dependencies

.github/workflows/ci.yaml actions
  • actions/checkout v2 composite
  • actions/setup-python v2 composite
  • casperdcl/deploy-pypi v2 composite
  • codecov/codecov-action v2 composite
pyproject.toml pypi