pyfaktory


Namepyfaktory JSON
Version 0.2.9 PyPI version JSON
download
home_pagehttps://github.com/ghilesmeddour/faktory_worker_python
SummaryFaktory Client Python (Producer and Consumer/Worker)
upload_time2024-12-16 11:43:45
maintainerNone
docs_urlNone
authorGhiles Meddour
requires_python<4.0,>=3.9
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Faktory Client Python (faktory_worker_python)

This repository provides Python Client (Consumer and Producer) for the [Faktory](https://github.com/contribsys/faktory/) background job server.

```
                   +--------------------+
                   |                    |
                   |     Faktory        |
                   |     Server         |
          +---->>>>|                    +>>>>----+
          |        |                    |        |
          |        |                    |        |
          |        +--------------------+        |
          |                                      |
          |                                      |
          |                                      |
          |                                      |
+-----------------------------------------------------------+     
|         .                Faktory               .          |            
|         .                Client                .          |  
|         .                                      .          |          
|   +-----------------+               +-----------------+   |
|   |                 |               |                 |   |
|   |    Producer     |               |    Consumer     |   |
|   |     pushes      |               |    (Worker)     |   |
|   |      jobs       |               |     fetches     |   |
|   |                 |               |       jobs      |   |
|   |                 |               |                 |   |
|   +-----------------+               +-----------------+   |          
|                                                           |            
+-----------------------------------------------------------+            
```

- [Server](https://github.com/contribsys/faktory/) - the Faktory daemon which stores background jobs in queues to be processed by Workers.
- Client - an entity that communicates with the Faktory server using the [FWP](https://github.com/contribsys/faktory/blob/master/docs/protocol-specification.md). A single client can act as both a consumer and a producer.
- Consumer (or Worker) - a client that fetches work units (jobs) from the server for execution.
- Producer - a client that issues new work units to the server.

This library tries to implement the [FWP](https://github.com/contribsys/faktory/blob/master/docs/protocol-specification.md) as well as possible. If you notice any inconsistencies, please report them.

## Installation

```
pip install pyfaktory
```

## Usage

### Faktory Server

If you have a Faktory server already running, make sure you have the correct url.

```python
# Default url for a Faktory server running locally
faktory_server_url = 'tcp://localhost:7419'
```

For the installation of faktory, please refer to [the official documentation](https://github.com/contribsys/faktory/wiki/Installation).

After installation, you can run it locally.

```console
$ /usr/bin/faktory
Faktory 1.8.0
```

You can use a password for the Faktory server via the environment variable `FAKTORY_PASSWORD`. Note if this value starts with a `/`, then it is considered a pointer to a file on the filesystem with the password. By default `/etc/faktory/password` is used.

The format of the Faktory URL is as follows:
```
tcp://:password@localhost:7419
```

You can access the [Fakotry GUI](http://localhost:7420/).

To run Faktory in production:
```
/usr/bin/faktory -e production
```

Faktory in production mode requires a password by default since version 0.7.0.

### Faktory Client

Import `pyfaktory`.

```python
from pyfaktory import Client, Consumer, Job, Producer
```

A single client can act as both a consumer and a producer. (You can enable IPv6 by setting `enable_ipv6` to `True`)

```python
client = Client(faktory_url='tcp://localhost:7419')
client.connect()

# Now you can use the client

# At the end, disconnect the client
client.disconnect()
```

Client is a context manager, so you can use `with` statement.

```python
with Client(faktory_url='tcp://localhost:7419') as client:
    # Use client
```

Use `role` argument to say how you want to use the client. This argument has 
three possible values: 'consumer', 'producer' or 'both'.

```python
# A client that acts as both a consumer and a producer.
client = Client(faktory_url='tcp://localhost:7419', role='both')
```

### Producer

Use the client to push jobs.

#### Push job

```python
with Client(faktory_url='tcp://localhost:7419', role='producer') as client:
    producer = Producer(client=client)
    job_1 = Job(jobtype='adder', args=(5, 4), queue='default')
    producer.push(job_1)
```

#### Push bulk jobs

You can push several jobs at once. There is no limit, but 1000 at a time is recommended as a best practice.

```python
with Client(faktory_url='tcp://localhost:7419', role='producer') as client:
    producer = Producer(client=client)
    job_2 = Job(jobtype='adder', args=(50, 41))
    job_3 = Job(jobtype='adder', args=(15, 68))
    res = producer.push_bulk([job_2, job_3])
```

### Consumer (Worker)

Use a worker to pull jobs from Faktory server and execute them.

```python
def adder(x, y):
    logging.info(f"{x} + {y} = {x + y}")

with Client(faktory_url='tcp://localhost:7419', role='consumer') as client:
    consumer = Consumer(client=client, queues=['default'], concurrency=1)
    consumer.register('adder', adder)
    consumer.run()
```

Use `priority` to indicates in which queue order the jobs should be fetched 
first.

```python
# With strict priority, there is a risk of starvation
consumer = Consumer(client=client, queues=['critical', 'default', 'bulk'], priority='strict')
# Each queue has an equal chance of being fetched first
consumer = Consumer(client=client, queues=['critical', 'default', 'bulk'], priority='uniform')
# Weights must be specified
consumer = Consumer(client=client, queues=['critical', 'default', 'bulk'], priority='weighted', weights=[0.6, 0.3, 0.1])
```

### Capture exceptions using Sentry

To capture exceptions using Sentry before failling jobs 
set `sentry_capture_exception` argument to `True`.

```python
consumer = Consumer(client=client, sentry_capture_exception=True)
```

### Info

You can get various information about the server using `info` Client method.

```python
with Client(faktory_url='tcp://localhost:7419') as client:
    server_info = client.info()
    print(server_info)
```

### Mutate

A wrapper for the [Mutate API](https://github.com/contribsys/faktory/wiki/Mutate-API) to script certain repairs or migrations.

⚠️ MUTATE commands can be slow and/or resource intensive. They should not be used as part of your application logic.

```python
from pyfaktory import Client, JobFilter, MutateOperation

client = Client(faktory_url='tcp://localhost:7419')
client.connect()

# Find all scheduled jobs with type `QuickbooksSyncJob` and discard them
op = MutateOperation(
    cmd='discard', 
    target='scheduled', 
    filter=JobFilter(jobtype="QuickbooksSyncJob")
)
client.mutate(op)

# Clear the Retry queue completely
op = MutateOperation(
    cmd='discard', 
    target='retries', 
    filter=JobFilter(regexp="*")
)
client.mutate(op)

# Clear the Retry queue completely
op = MutateOperation(
    cmd='discard', 
    target='retries'
)
client.mutate(op)

# Send a two specific JIDs in the Retry queue to the Dead queue
op = MutateOperation(
    cmd='kill', 
    target='retries', 
    filter=JobFilter(jobtype="QuickbooksSyncJob", jids=["123456789", "abcdefgh"])
)
client.mutate(op)

# Enqueue all retries with a first argument matching "bob"
op = MutateOperation(
    cmd='requeue', 
    target='retries', 
    filter=JobFilter(regexp="*\"args\":[\"bob\"*")
)
client.mutate(op)

client.disconnect()
```

### Queues

**Pausing**

Queues may be paused (no job can be fetched from them while paused) or unpaused 
(resume fetching).

```python
# Pause a list of queues
client.queue_pause(queues=['bulk', 'another_queue'])

# Pause all queues
client.queue_pause(all_queues=True)


# Unpause a list of queues
client.queue_unpause(queues=['bulk'])

# Unpause all queues
client.queue_unpause(all_queues=True)
```

**Remove**

Queues can be removed which deletes all jobs within them. It does not stop 
currently executing jobs from those queues.

```python
# Remove a list of queues
client.queue_remove(queues=['bulk'])

# Remove all queues
client.queue_remove(all_queues=True)
```

### Batch (untested)

Refer to [documentation](https://github.com/contribsys/faktory/wiki/Ent-Batches).

```python
from pyfaktory import Batch, Client, Job, Producer, TargetJob

client = Client(faktory_url='tcp://localhost:7419')
client.connect()

producer = Producer(client=client)

batch = Batch(
    description="An optional description for the Web UI",
    success=TargetJob(jobtype="MySuccessCallback", args=[123], queue="critical"),
    complete=TargetJob(jobtype="MyCompleteCallback", args=['aa'], queue="critical")
)

# Create a new batch
resp = producer.batch_new(batch)

# Push as many jobs as necessary for the batch
# You may nest batches
# The initial batch data has a TTL of 30 minutes and will expire if batch is not commited
producer.push(Job(jobtype='SomeJob', args=(5, 4), custom={"bid": bid}))
producer.push(Job(jobtype='SomeOtherJob', args=(0, 15), custom={"bid": bid}))

# Commit the batch
producer.batch_commit(bid)

client.disconnect()
```

Use `batch_open` to open a created batch.

```python
producer.batch_open(bid)
```

Use `parent_bid` for child batch.

```python
child_batch = Batch(
    parent_bid=bid,
    description="An optional description for the Web UI",
    success=TargetJob(jobtype="MySuccessCallback", args=[123], queue="critical"),
    complete=TargetJob(jobtype="MyCompleteCallback", args=['aa'], queue="critical")
)
```

### Custom command

If you want to use a Faktory command that is not yet implemented in this client library, you can send custom commands.

```python
from pyfaktory import Client

my_command = 'INFO\r\n'

with Client(faktory_url='tcp://localhost:7419') as client:
    resp = client._send_and_receive(my_command)
    print(resp)
```

### Outer multiprocessing

You can use outer multiprocessing.

```python
def run_worker():
    try:
        with Client(faktory_url=faktory_server_url, role='consumer') as client:
            import multiprocessing
            custom_context = multiprocessing.get_context("spawn")
            consumer = Consumer(client=client, queues=['t_test'], concurrency=2, context=custom_context)
            consumer.register('task_001', task_001)
            consumer.run()
    except Exception as e:
        print(f"task running error: {str(e)}")
```

## Example

Find examples in `./examples`.

- Start the Faktory server.
```
/usr/bin/faktory
```

- Launch a producer.
```
python examples/fproducer.py
```

- Launch a consumer.
```
python examples/fconsumer.py
```

- Look at what is happening in the logs and in the [Faktory Web UI](http://localhost:7420/).

## Contribute

### Issues

If you encounter a problem, please report it.

In addition to the description of your problem, report the server and client
versions.

```python
pyfaktory.__version__
```
```
/usr/bin/faktory -v
```

Reproduce your problem while increasing the level of debugging for both the
server and the client, and report the logs.
```python
import logging

logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s',
                    level=logging.DEBUG,
                    datefmt='%Y-%m-%d %H:%M:%S')
```
```
/usr/bin/faktory -l debug
```

### PRs

Please, feel free to create pull requests.

## License

See the [LICENSE](LICENSE.md) file for license rights and limitations (MIT).

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ghilesmeddour/faktory_worker_python",
    "name": "pyfaktory",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.9",
    "maintainer_email": null,
    "keywords": null,
    "author": "Ghiles Meddour",
    "author_email": "ghiles.meddour.b@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/95/ac/9607af2bef6e9b7ed8097bbf179b1d01fefd27e9320115c4a3daef82b89b/pyfaktory-0.2.9.tar.gz",
    "platform": null,
    "description": "# Faktory Client Python (faktory_worker_python)\n\nThis repository provides Python Client (Consumer and Producer) for the [Faktory](https://github.com/contribsys/faktory/) background job server.\n\n```\n                   +--------------------+\n                   |                    |\n                   |     Faktory        |\n                   |     Server         |\n          +---->>>>|                    +>>>>----+\n          |        |                    |        |\n          |        |                    |        |\n          |        +--------------------+        |\n          |                                      |\n          |                                      |\n          |                                      |\n          |                                      |\n+-----------------------------------------------------------+     \n|         .                Faktory               .          |            \n|         .                Client                .          |  \n|         .                                      .          |          \n|   +-----------------+               +-----------------+   |\n|   |                 |               |                 |   |\n|   |    Producer     |               |    Consumer     |   |\n|   |     pushes      |               |    (Worker)     |   |\n|   |      jobs       |               |     fetches     |   |\n|   |                 |               |       jobs      |   |\n|   |                 |               |                 |   |\n|   +-----------------+               +-----------------+   |          \n|                                                           |            \n+-----------------------------------------------------------+            \n```\n\n- [Server](https://github.com/contribsys/faktory/) - the Faktory daemon which stores background jobs in queues to be processed by Workers.\n- Client - an entity that communicates with the Faktory server using the [FWP](https://github.com/contribsys/faktory/blob/master/docs/protocol-specification.md). A single client can act as both a consumer and a producer.\n- Consumer (or Worker) - a client that fetches work units (jobs) from the server for execution.\n- Producer - a client that issues new work units to the server.\n\nThis library tries to implement the [FWP](https://github.com/contribsys/faktory/blob/master/docs/protocol-specification.md) as well as possible. If you notice any inconsistencies, please report them.\n\n## Installation\n\n```\npip install pyfaktory\n```\n\n## Usage\n\n### Faktory Server\n\nIf you have a Faktory server already running, make sure you have the correct url.\n\n```python\n# Default url for a Faktory server running locally\nfaktory_server_url = 'tcp://localhost:7419'\n```\n\nFor the installation of faktory, please refer to [the official documentation](https://github.com/contribsys/faktory/wiki/Installation).\n\nAfter installation, you can run it locally.\n\n```console\n$ /usr/bin/faktory\nFaktory 1.8.0\n```\n\nYou can use a password for the Faktory server via the environment variable `FAKTORY_PASSWORD`. Note if this value starts with a `/`, then it is considered a pointer to a file on the filesystem with the password. By default `/etc/faktory/password` is used.\n\nThe format of the Faktory URL is as follows:\n```\ntcp://:password@localhost:7419\n```\n\nYou can access the [Fakotry GUI](http://localhost:7420/).\n\nTo run Faktory in production:\n```\n/usr/bin/faktory -e production\n```\n\nFaktory in production mode requires a password by default since version 0.7.0.\n\n### Faktory Client\n\nImport `pyfaktory`.\n\n```python\nfrom pyfaktory import Client, Consumer, Job, Producer\n```\n\nA single client can act as both a consumer and a producer. (You can enable IPv6 by setting `enable_ipv6` to `True`)\n\n```python\nclient = Client(faktory_url='tcp://localhost:7419')\nclient.connect()\n\n# Now you can use the client\n\n# At the end, disconnect the client\nclient.disconnect()\n```\n\nClient is a context manager, so you can use `with` statement.\n\n```python\nwith Client(faktory_url='tcp://localhost:7419') as client:\n    # Use client\n```\n\nUse `role` argument to say how you want to use the client. This argument has \nthree possible values: 'consumer', 'producer' or 'both'.\n\n```python\n# A client that acts as both a consumer and a producer.\nclient = Client(faktory_url='tcp://localhost:7419', role='both')\n```\n\n### Producer\n\nUse the client to push jobs.\n\n#### Push job\n\n```python\nwith Client(faktory_url='tcp://localhost:7419', role='producer') as client:\n    producer = Producer(client=client)\n    job_1 = Job(jobtype='adder', args=(5, 4), queue='default')\n    producer.push(job_1)\n```\n\n#### Push bulk jobs\n\nYou can push several jobs at once. There is no limit, but 1000 at a time is recommended as a best practice.\n\n```python\nwith Client(faktory_url='tcp://localhost:7419', role='producer') as client:\n    producer = Producer(client=client)\n    job_2 = Job(jobtype='adder', args=(50, 41))\n    job_3 = Job(jobtype='adder', args=(15, 68))\n    res = producer.push_bulk([job_2, job_3])\n```\n\n### Consumer (Worker)\n\nUse a worker to pull jobs from Faktory server and execute them.\n\n```python\ndef adder(x, y):\n    logging.info(f\"{x} + {y} = {x + y}\")\n\nwith Client(faktory_url='tcp://localhost:7419', role='consumer') as client:\n    consumer = Consumer(client=client, queues=['default'], concurrency=1)\n    consumer.register('adder', adder)\n    consumer.run()\n```\n\nUse `priority` to indicates in which queue order the jobs should be fetched \nfirst.\n\n```python\n# With strict priority, there is a risk of starvation\nconsumer = Consumer(client=client, queues=['critical', 'default', 'bulk'], priority='strict')\n# Each queue has an equal chance of being fetched first\nconsumer = Consumer(client=client, queues=['critical', 'default', 'bulk'], priority='uniform')\n# Weights must be specified\nconsumer = Consumer(client=client, queues=['critical', 'default', 'bulk'], priority='weighted', weights=[0.6, 0.3, 0.1])\n```\n\n### Capture exceptions using Sentry\n\nTo capture exceptions using Sentry before failling jobs \nset `sentry_capture_exception` argument to `True`.\n\n```python\nconsumer = Consumer(client=client, sentry_capture_exception=True)\n```\n\n### Info\n\nYou can get various information about the server using `info` Client method.\n\n```python\nwith Client(faktory_url='tcp://localhost:7419') as client:\n    server_info = client.info()\n    print(server_info)\n```\n\n### Mutate\n\nA wrapper for the [Mutate API](https://github.com/contribsys/faktory/wiki/Mutate-API) to script certain repairs or migrations.\n\n\u26a0\ufe0f MUTATE commands can be slow and/or resource intensive. They should not be used as part of your application logic.\n\n```python\nfrom pyfaktory import Client, JobFilter, MutateOperation\n\nclient = Client(faktory_url='tcp://localhost:7419')\nclient.connect()\n\n# Find all scheduled jobs with type `QuickbooksSyncJob` and discard them\nop = MutateOperation(\n    cmd='discard', \n    target='scheduled', \n    filter=JobFilter(jobtype=\"QuickbooksSyncJob\")\n)\nclient.mutate(op)\n\n# Clear the Retry queue completely\nop = MutateOperation(\n    cmd='discard', \n    target='retries', \n    filter=JobFilter(regexp=\"*\")\n)\nclient.mutate(op)\n\n# Clear the Retry queue completely\nop = MutateOperation(\n    cmd='discard', \n    target='retries'\n)\nclient.mutate(op)\n\n# Send a two specific JIDs in the Retry queue to the Dead queue\nop = MutateOperation(\n    cmd='kill', \n    target='retries', \n    filter=JobFilter(jobtype=\"QuickbooksSyncJob\", jids=[\"123456789\", \"abcdefgh\"])\n)\nclient.mutate(op)\n\n# Enqueue all retries with a first argument matching \"bob\"\nop = MutateOperation(\n    cmd='requeue', \n    target='retries', \n    filter=JobFilter(regexp=\"*\\\"args\\\":[\\\"bob\\\"*\")\n)\nclient.mutate(op)\n\nclient.disconnect()\n```\n\n### Queues\n\n**Pausing**\n\nQueues may be paused (no job can be fetched from them while paused) or unpaused \n(resume fetching).\n\n```python\n# Pause a list of queues\nclient.queue_pause(queues=['bulk', 'another_queue'])\n\n# Pause all queues\nclient.queue_pause(all_queues=True)\n\n\n# Unpause a list of queues\nclient.queue_unpause(queues=['bulk'])\n\n# Unpause all queues\nclient.queue_unpause(all_queues=True)\n```\n\n**Remove**\n\nQueues can be removed which deletes all jobs within them. It does not stop \ncurrently executing jobs from those queues.\n\n```python\n# Remove a list of queues\nclient.queue_remove(queues=['bulk'])\n\n# Remove all queues\nclient.queue_remove(all_queues=True)\n```\n\n### Batch (untested)\n\nRefer to [documentation](https://github.com/contribsys/faktory/wiki/Ent-Batches).\n\n```python\nfrom pyfaktory import Batch, Client, Job, Producer, TargetJob\n\nclient = Client(faktory_url='tcp://localhost:7419')\nclient.connect()\n\nproducer = Producer(client=client)\n\nbatch = Batch(\n    description=\"An optional description for the Web UI\",\n    success=TargetJob(jobtype=\"MySuccessCallback\", args=[123], queue=\"critical\"),\n    complete=TargetJob(jobtype=\"MyCompleteCallback\", args=['aa'], queue=\"critical\")\n)\n\n# Create a new batch\nresp = producer.batch_new(batch)\n\n# Push as many jobs as necessary for the batch\n# You may nest batches\n# The initial batch data has a TTL of 30 minutes and will expire if batch is not commited\nproducer.push(Job(jobtype='SomeJob', args=(5, 4), custom={\"bid\": bid}))\nproducer.push(Job(jobtype='SomeOtherJob', args=(0, 15), custom={\"bid\": bid}))\n\n# Commit the batch\nproducer.batch_commit(bid)\n\nclient.disconnect()\n```\n\nUse `batch_open` to open a created batch.\n\n```python\nproducer.batch_open(bid)\n```\n\nUse `parent_bid` for child batch.\n\n```python\nchild_batch = Batch(\n    parent_bid=bid,\n    description=\"An optional description for the Web UI\",\n    success=TargetJob(jobtype=\"MySuccessCallback\", args=[123], queue=\"critical\"),\n    complete=TargetJob(jobtype=\"MyCompleteCallback\", args=['aa'], queue=\"critical\")\n)\n```\n\n### Custom command\n\nIf you want to use a Faktory command that is not yet implemented in this client library, you can send custom commands.\n\n```python\nfrom pyfaktory import Client\n\nmy_command = 'INFO\\r\\n'\n\nwith Client(faktory_url='tcp://localhost:7419') as client:\n    resp = client._send_and_receive(my_command)\n    print(resp)\n```\n\n### Outer multiprocessing\n\nYou can use outer multiprocessing.\n\n```python\ndef run_worker():\n    try:\n        with Client(faktory_url=faktory_server_url, role='consumer') as client:\n            import multiprocessing\n            custom_context = multiprocessing.get_context(\"spawn\")\n            consumer = Consumer(client=client, queues=['t_test'], concurrency=2, context=custom_context)\n            consumer.register('task_001', task_001)\n            consumer.run()\n    except Exception as e:\n        print(f\"task running error: {str(e)}\")\n```\n\n## Example\n\nFind examples in `./examples`.\n\n- Start the Faktory server.\n```\n/usr/bin/faktory\n```\n\n- Launch a producer.\n```\npython examples/fproducer.py\n```\n\n- Launch a consumer.\n```\npython examples/fconsumer.py\n```\n\n- Look at what is happening in the logs and in the [Faktory Web UI](http://localhost:7420/).\n\n## Contribute\n\n### Issues\n\nIf you encounter a problem, please report it.\n\nIn addition to the description of your problem, report the server and client\nversions.\n\n```python\npyfaktory.__version__\n```\n```\n/usr/bin/faktory -v\n```\n\nReproduce your problem while increasing the level of debugging for both the\nserver and the client, and report the logs.\n```python\nimport logging\n\nlogging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s',\n                    level=logging.DEBUG,\n                    datefmt='%Y-%m-%d %H:%M:%S')\n```\n```\n/usr/bin/faktory -l debug\n```\n\n### PRs\n\nPlease, feel free to create pull requests.\n\n## License\n\nSee the [LICENSE](LICENSE.md) file for license rights and limitations (MIT).\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Faktory Client Python (Producer and Consumer/Worker)",
    "version": "0.2.9",
    "project_urls": {
        "Documentation": "https://github.com/ghilesmeddour/faktory_worker_python",
        "Homepage": "https://github.com/ghilesmeddour/faktory_worker_python",
        "Repository": "https://github.com/ghilesmeddour/faktory_worker_python"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7afcd8b073506e12d4755c57e5d256e466115733b0575a2a98bc4740558fabc1",
                "md5": "314e50c1099ce87db1d935627dcf4559",
                "sha256": "e7a9a7a18038a538fa4b2de11e2472d7445b01c5c779d2679a5c4c68d8aa0872"
            },
            "downloads": -1,
            "filename": "pyfaktory-0.2.9-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "314e50c1099ce87db1d935627dcf4559",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.9",
            "size": 17756,
            "upload_time": "2024-12-16T11:43:42",
            "upload_time_iso_8601": "2024-12-16T11:43:42.993358Z",
            "url": "https://files.pythonhosted.org/packages/7a/fc/d8b073506e12d4755c57e5d256e466115733b0575a2a98bc4740558fabc1/pyfaktory-0.2.9-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "95ac9607af2bef6e9b7ed8097bbf179b1d01fefd27e9320115c4a3daef82b89b",
                "md5": "a5e020027920928cb6144a143b67f1ea",
                "sha256": "c8bb2d862cffd7112ad088c8b4bfcb2b0d4df4cd31e519b0872501a01a6c5afb"
            },
            "downloads": -1,
            "filename": "pyfaktory-0.2.9.tar.gz",
            "has_sig": false,
            "md5_digest": "a5e020027920928cb6144a143b67f1ea",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.9",
            "size": 17762,
            "upload_time": "2024-12-16T11:43:45",
            "upload_time_iso_8601": "2024-12-16T11:43:45.610576Z",
            "url": "https://files.pythonhosted.org/packages/95/ac/9607af2bef6e9b7ed8097bbf179b1d01fefd27e9320115c4a3daef82b89b/pyfaktory-0.2.9.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-16 11:43:45",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ghilesmeddour",
    "github_project": "faktory_worker_python",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "pyfaktory"
}
        
Elapsed time: 0.36209s