schedq 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
schedq-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.4
2
+ Name: schedq
3
+ Version: 0.0.1
4
+ Summary: Lightweight, high-performance asynchronous task scheduling engine with no external dependencies.
5
+ Author-email: "Élcio M. Fernandes" <elciomfer@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Framework :: AsyncIO
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+
13
+ # schedq
14
+
15
+ O **schedq** é um motor de agendamento de tarefas assíncronas em Python que foca em ser **extremamente leve, performático e independente**. Utilizando exclusivamente primitivas nativas da linguagem e estruturas de dados de alta performance, ele elimina a necessidade de infraestruturas pesadas para cenários concorrentes.
16
+
17
+ Inspirado na usabilidade moderna baseada em decoradores (como Prefect) e na eficiência matemática de baixo nível (uso de Filas de Prioridade), o schedq oferece controle total do tempo sem desperdício de CPU.
18
+
19
+ ---
20
+
21
+ ## Recursos Atuais (O que ele já faz)
22
+
23
+ - **Agendamento por Min-Heap:** Organização interna baseada no módulo nativo `heapq` rodando em C. O motor avalia apenas o topo da árvore (O(1)) e dorme o tempo exato até a próxima tarefa, resultando em **0% de uso de CPU** ociosa.
24
+ - **Concorrência Assíncrona:** Construído sobre o `asyncio`. Execuções demoradas são disparadas como _background tasks_, impedindo que uma tarefa lenta atrase o relógio das demais.
25
+ - **Rastreamento por IDs (Observabilidade):** Separação nativa entre **TID** (Task ID, fixo para a definição da tarefa) e **EID** (Execution ID, único para cada ciclo de execução), ideal para estruturação de logs.
26
+ - **Interface Fluida (Decoradores):** Sintaxe amigável e limpa para registro de rotinas com suporte a nomes customizados opcionais.
27
+
28
+ ---
29
+
30
+ ## Roadmap de Evolução (Próximos Passos)
31
+
32
+ Para transformar este motor leve em um orquestrador resiliente e pronto para ambientes críticos de produção, planejamos implementar os seguintes módulos de forma incremental:
33
+
34
+ ### 1. Módulo de Persistência (Resiliência)
35
+
36
+ _Atualmente as tarefas vivem apenas na memória volátil do processo._
37
+
38
+ - **Objetivo:** Adicionar adaptadores opcionais para armazenamento de estados (ex: SQLite integrado ou Redis).
39
+ - **Recurso:** Mecanismo de **Misfire** para decidir o que fazer se o servidor reiniciar e perder a janela exata de execução de uma tarefa.
40
+
41
+ ### 2. Módulo de Tolerância a Falhas (Retries & Circuit Breaker)
42
+
43
+ _Atualmente Exceptions dentro de uma task somem silenciosamente._
44
+
45
+ - **Objetivo:** Capturar erros em nível de execução sem derrubar o loop principal do motor.
46
+ - **Recurso:** Implementação de políticas de **Exponential Backoff** (tentativas automáticas com espaçamento de tempo crescente) e alertas para falhas definitivas.
47
+
48
+ ### 3. Módulo de Controle de Concorrência (Limitação de Instâncias)
49
+
50
+ _Atualmente, se uma tarefa a cada 5s demorar 20s para rodar, o motor criará instâncias paralelas descontroladamente._
51
+
52
+ - **Objetivo:** Introduzir a propriedade `max_instances`.
53
+ - **Recurso:** Permitir que o motor pule (_skip_) ou enfileire o próximo disparo caso a instância anterior da mesma tarefa ainda esteja sendo executada.
54
+
55
+ ### 4. Módulo de Controle Dinâmico (Gerenciamento em Runtime)
56
+
57
+ _Atualmente o motor roda em uma caixa preta após o `.start()`._
58
+
59
+ - **Objetivo:** Criar uma API programática para manipulação das tarefas em tempo real.
60
+ - **Recurso:** Métodos como `sched.pause(tid)`, `sched.resume(tid)` e `sched.trigger_now(tid)` para forçar a execução imediata ignorando o relógio.
61
+
62
+ ### 5. Expressões Cron e Suporte a Fusos Horários (Timezones)
63
+
64
+ _Atualmente o motor suporta apenas intervalos relativos (`timedelta`)._
65
+
66
+ - **Objetivo:** Integração com parsers de Cron leves para agendamentos em horários humanos específicos (ex: "Toda segunda-feira às 08:00").
67
+ - **Recurso:** Tratamento nativo de Timezones para evitar desvios causados por fusos horários de servidores (UTC) ou horários de verão.
68
+
69
+ ---
70
+
71
+ ## Como Usar (Exemplo de Implementação)
72
+
73
+ ```python
74
+ import asyncio
75
+ import datetime
76
+ from scheduler import Scheduler
77
+
78
+ sched = Scheduler()
79
+
80
+ @sched.task(interval=datetime.timedelta(seconds=4), name="Task name")
81
+ async def example(tid: str, eid: str, name: str):
82
+ # Logic here
83
+ await asyncio.sleep(1)
84
+
85
+ async def main():
86
+ await sched.start()
87
+
88
+ if __name__ == "__main__":
89
+ asyncio.run(main())
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Diretrizes de Design
95
+
96
+ 1. **Zero Bloqueio:** Nenhuma função síncrona ou método (`time.sleep`) deve interceptar o loop principal.
97
+ 2. **Dependência Opcional:** Recursos mais pesados (como bancos de dados para persistência) devem ser plugáveis e opcionais para manter o core do motor sempre leve.
98
+ 3. **Foco na Developer Experience (DX):** A complexidade matemática e de concorrência deve sempre ficar escondida sob os panos do motor.
schedq-0.0.1/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # schedq
2
+
3
+ O **schedq** é um motor de agendamento de tarefas assíncronas em Python que foca em ser **extremamente leve, performático e independente**. Utilizando exclusivamente primitivas nativas da linguagem e estruturas de dados de alta performance, ele elimina a necessidade de infraestruturas pesadas para cenários concorrentes.
4
+
5
+ Inspirado na usabilidade moderna baseada em decoradores (como Prefect) e na eficiência matemática de baixo nível (uso de Filas de Prioridade), o schedq oferece controle total do tempo sem desperdício de CPU.
6
+
7
+ ---
8
+
9
+ ## Recursos Atuais (O que ele já faz)
10
+
11
+ - **Agendamento por Min-Heap:** Organização interna baseada no módulo nativo `heapq` rodando em C. O motor avalia apenas o topo da árvore (O(1)) e dorme o tempo exato até a próxima tarefa, resultando em **0% de uso de CPU** ociosa.
12
+ - **Concorrência Assíncrona:** Construído sobre o `asyncio`. Execuções demoradas são disparadas como _background tasks_, impedindo que uma tarefa lenta atrase o relógio das demais.
13
+ - **Rastreamento por IDs (Observabilidade):** Separação nativa entre **TID** (Task ID, fixo para a definição da tarefa) e **EID** (Execution ID, único para cada ciclo de execução), ideal para estruturação de logs.
14
+ - **Interface Fluida (Decoradores):** Sintaxe amigável e limpa para registro de rotinas com suporte a nomes customizados opcionais.
15
+
16
+ ---
17
+
18
+ ## Roadmap de Evolução (Próximos Passos)
19
+
20
+ Para transformar este motor leve em um orquestrador resiliente e pronto para ambientes críticos de produção, planejamos implementar os seguintes módulos de forma incremental:
21
+
22
+ ### 1. Módulo de Persistência (Resiliência)
23
+
24
+ _Atualmente as tarefas vivem apenas na memória volátil do processo._
25
+
26
+ - **Objetivo:** Adicionar adaptadores opcionais para armazenamento de estados (ex: SQLite integrado ou Redis).
27
+ - **Recurso:** Mecanismo de **Misfire** para decidir o que fazer se o servidor reiniciar e perder a janela exata de execução de uma tarefa.
28
+
29
+ ### 2. Módulo de Tolerância a Falhas (Retries & Circuit Breaker)
30
+
31
+ _Atualmente Exceptions dentro de uma task somem silenciosamente._
32
+
33
+ - **Objetivo:** Capturar erros em nível de execução sem derrubar o loop principal do motor.
34
+ - **Recurso:** Implementação de políticas de **Exponential Backoff** (tentativas automáticas com espaçamento de tempo crescente) e alertas para falhas definitivas.
35
+
36
+ ### 3. Módulo de Controle de Concorrência (Limitação de Instâncias)
37
+
38
+ _Atualmente, se uma tarefa a cada 5s demorar 20s para rodar, o motor criará instâncias paralelas descontroladamente._
39
+
40
+ - **Objetivo:** Introduzir a propriedade `max_instances`.
41
+ - **Recurso:** Permitir que o motor pule (_skip_) ou enfileire o próximo disparo caso a instância anterior da mesma tarefa ainda esteja sendo executada.
42
+
43
+ ### 4. Módulo de Controle Dinâmico (Gerenciamento em Runtime)
44
+
45
+ _Atualmente o motor roda em uma caixa preta após o `.start()`._
46
+
47
+ - **Objetivo:** Criar uma API programática para manipulação das tarefas em tempo real.
48
+ - **Recurso:** Métodos como `sched.pause(tid)`, `sched.resume(tid)` e `sched.trigger_now(tid)` para forçar a execução imediata ignorando o relógio.
49
+
50
+ ### 5. Expressões Cron e Suporte a Fusos Horários (Timezones)
51
+
52
+ _Atualmente o motor suporta apenas intervalos relativos (`timedelta`)._
53
+
54
+ - **Objetivo:** Integração com parsers de Cron leves para agendamentos em horários humanos específicos (ex: "Toda segunda-feira às 08:00").
55
+ - **Recurso:** Tratamento nativo de Timezones para evitar desvios causados por fusos horários de servidores (UTC) ou horários de verão.
56
+
57
+ ---
58
+
59
+ ## Como Usar (Exemplo de Implementação)
60
+
61
+ ```python
62
+ import asyncio
63
+ import datetime
64
+ from scheduler import Scheduler
65
+
66
+ sched = Scheduler()
67
+
68
+ @sched.task(interval=datetime.timedelta(seconds=4), name="Task name")
69
+ async def example(tid: str, eid: str, name: str):
70
+ # Logic here
71
+ await asyncio.sleep(1)
72
+
73
+ async def main():
74
+ await sched.start()
75
+
76
+ if __name__ == "__main__":
77
+ asyncio.run(main())
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Diretrizes de Design
83
+
84
+ 1. **Zero Bloqueio:** Nenhuma função síncrona ou método (`time.sleep`) deve interceptar o loop principal.
85
+ 2. **Dependência Opcional:** Recursos mais pesados (como bancos de dados para persistência) devem ser plugáveis e opcionais para manter o core do motor sempre leve.
86
+ 3. **Foco na Developer Experience (DX):** A complexidade matemática e de concorrência deve sempre ficar escondida sob os panos do motor.
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "schedq"
7
+ version = "0.0.1"
8
+ description = "Lightweight, high-performance asynchronous task scheduling engine with no external dependencies."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ authors = [
12
+ { name="Élcio M. Fernandes", email="elciomfer@gmail.com" }
13
+ ]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Framework :: AsyncIO",
19
+ ]
@@ -0,0 +1 @@
1
+ from .core import Schedq, Task
@@ -0,0 +1,100 @@
1
+ import asyncio
2
+ import dataclasses
3
+ import datetime
4
+ import heapq
5
+ import uuid
6
+ import typing
7
+
8
+ @dataclasses.dataclass(order=True)
9
+ class Task:
10
+ exectime: datetime.datetime
11
+
12
+ tid: str = dataclasses.field(compare=False)
13
+ name: str = dataclasses.field(compare=False)
14
+ interval: datetime.timedelta = dataclasses.field(compare=False)
15
+ ispaused: bool = dataclasses.field(compare=False, default=False)
16
+ taskfunc: typing.Callable[..., typing.Coroutine] = dataclasses.field(compare=False)
17
+
18
+ class Schedq:
19
+ def __init__(self) -> None:
20
+ self.mainloop = None
21
+ self.minheap = []
22
+ self.taskmap = {}
23
+ self.trigger = asyncio.Event()
24
+
25
+ def _add(self, tid: str, name: str, interval: datetime.timedelta, function: typing.Callable[..., typing.Coroutine]):
26
+ newtask = Task(datetime.datetime.now() + interval, tid, name, function, interval)
27
+
28
+ heapq.heappush(self.minheap, newtask)
29
+ self.taskmap[tid] = newtask
30
+
31
+ if self.mainloop:
32
+ self.trigger.set()
33
+
34
+ def flow(self):
35
+ def decorator(func: typing.Callable[..., typing.Coroutine]):
36
+ pass
37
+ return func
38
+ return decorator
39
+
40
+ def task(self, interval: datetime.timedelta, name: typing.Optional[str] = None):
41
+ def decorator(func: typing.Callable[..., typing.Coroutine]):
42
+ self._add(str(uuid.uuid4()), name or func.__name__, interval, func)
43
+ return func
44
+ return decorator
45
+
46
+ def pause(self, tid: str):
47
+ if tid in self.taskmap:
48
+ self.taskmap[tid].ispaused = True
49
+
50
+ def resume(self, tid: str):
51
+ if tid in self.taskmap:
52
+ self.taskmap[tid].ispaused = False
53
+
54
+ def invoke(self, tid: str):
55
+ if tid in self.taskmap:
56
+ self.taskmap[tid].exectime = datetime.datetime.now()
57
+ heapq.heapify(self.minheap)
58
+
59
+ if self.mainloop:
60
+ self.trigger.set()
61
+
62
+ async def start(self):
63
+ self.mainloop = asyncio.get_running_loop()
64
+
65
+ while True:
66
+ self.trigger.clear()
67
+
68
+ if not self.minheap:
69
+ await self.trigger.wait()
70
+ continue
71
+
72
+ now = datetime.datetime.now()
73
+ headtask = self.minheap[0]
74
+
75
+ if now >= headtask.exectime:
76
+ task = heapq.heappop(self.minheap)
77
+
78
+ if not task.ispaused:
79
+ eid = str(uuid.uuid4())
80
+
81
+ async def taskrun(t=task, e=eid):
82
+ print(f"[RUNNING] Task: {t.name} - TID: {t.tid} - EID: {e}")
83
+ try:
84
+ await t.taskfunc(t.tid, e, t.name)
85
+ print(f"[SUCCESS] Task: {t.name} - EID: {e}")
86
+ except Exception as err:
87
+ print(f"[FAILED] Task: {t.name} - EID: {e} - Error: {err}")
88
+
89
+ asyncio.create_task(taskrun())
90
+
91
+ task.exectime = now + task.interval
92
+ heapq.heappush(self.minheap, task)
93
+ else:
94
+ leftover = (headtask.exectime - now).total_seconds()
95
+
96
+ if leftover > 0:
97
+ try:
98
+ await asyncio.wait_for(self.trigger.wait(), timeout=leftover)
99
+ except asyncio.TimeoutError:
100
+ pass
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.4
2
+ Name: schedq
3
+ Version: 0.0.1
4
+ Summary: Lightweight, high-performance asynchronous task scheduling engine with no external dependencies.
5
+ Author-email: "Élcio M. Fernandes" <elciomfer@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Framework :: AsyncIO
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+
13
+ # schedq
14
+
15
+ O **schedq** é um motor de agendamento de tarefas assíncronas em Python que foca em ser **extremamente leve, performático e independente**. Utilizando exclusivamente primitivas nativas da linguagem e estruturas de dados de alta performance, ele elimina a necessidade de infraestruturas pesadas para cenários concorrentes.
16
+
17
+ Inspirado na usabilidade moderna baseada em decoradores (como Prefect) e na eficiência matemática de baixo nível (uso de Filas de Prioridade), o schedq oferece controle total do tempo sem desperdício de CPU.
18
+
19
+ ---
20
+
21
+ ## Recursos Atuais (O que ele já faz)
22
+
23
+ - **Agendamento por Min-Heap:** Organização interna baseada no módulo nativo `heapq` rodando em C. O motor avalia apenas o topo da árvore (O(1)) e dorme o tempo exato até a próxima tarefa, resultando em **0% de uso de CPU** ociosa.
24
+ - **Concorrência Assíncrona:** Construído sobre o `asyncio`. Execuções demoradas são disparadas como _background tasks_, impedindo que uma tarefa lenta atrase o relógio das demais.
25
+ - **Rastreamento por IDs (Observabilidade):** Separação nativa entre **TID** (Task ID, fixo para a definição da tarefa) e **EID** (Execution ID, único para cada ciclo de execução), ideal para estruturação de logs.
26
+ - **Interface Fluida (Decoradores):** Sintaxe amigável e limpa para registro de rotinas com suporte a nomes customizados opcionais.
27
+
28
+ ---
29
+
30
+ ## Roadmap de Evolução (Próximos Passos)
31
+
32
+ Para transformar este motor leve em um orquestrador resiliente e pronto para ambientes críticos de produção, planejamos implementar os seguintes módulos de forma incremental:
33
+
34
+ ### 1. Módulo de Persistência (Resiliência)
35
+
36
+ _Atualmente as tarefas vivem apenas na memória volátil do processo._
37
+
38
+ - **Objetivo:** Adicionar adaptadores opcionais para armazenamento de estados (ex: SQLite integrado ou Redis).
39
+ - **Recurso:** Mecanismo de **Misfire** para decidir o que fazer se o servidor reiniciar e perder a janela exata de execução de uma tarefa.
40
+
41
+ ### 2. Módulo de Tolerância a Falhas (Retries & Circuit Breaker)
42
+
43
+ _Atualmente Exceptions dentro de uma task somem silenciosamente._
44
+
45
+ - **Objetivo:** Capturar erros em nível de execução sem derrubar o loop principal do motor.
46
+ - **Recurso:** Implementação de políticas de **Exponential Backoff** (tentativas automáticas com espaçamento de tempo crescente) e alertas para falhas definitivas.
47
+
48
+ ### 3. Módulo de Controle de Concorrência (Limitação de Instâncias)
49
+
50
+ _Atualmente, se uma tarefa a cada 5s demorar 20s para rodar, o motor criará instâncias paralelas descontroladamente._
51
+
52
+ - **Objetivo:** Introduzir a propriedade `max_instances`.
53
+ - **Recurso:** Permitir que o motor pule (_skip_) ou enfileire o próximo disparo caso a instância anterior da mesma tarefa ainda esteja sendo executada.
54
+
55
+ ### 4. Módulo de Controle Dinâmico (Gerenciamento em Runtime)
56
+
57
+ _Atualmente o motor roda em uma caixa preta após o `.start()`._
58
+
59
+ - **Objetivo:** Criar uma API programática para manipulação das tarefas em tempo real.
60
+ - **Recurso:** Métodos como `sched.pause(tid)`, `sched.resume(tid)` e `sched.trigger_now(tid)` para forçar a execução imediata ignorando o relógio.
61
+
62
+ ### 5. Expressões Cron e Suporte a Fusos Horários (Timezones)
63
+
64
+ _Atualmente o motor suporta apenas intervalos relativos (`timedelta`)._
65
+
66
+ - **Objetivo:** Integração com parsers de Cron leves para agendamentos em horários humanos específicos (ex: "Toda segunda-feira às 08:00").
67
+ - **Recurso:** Tratamento nativo de Timezones para evitar desvios causados por fusos horários de servidores (UTC) ou horários de verão.
68
+
69
+ ---
70
+
71
+ ## Como Usar (Exemplo de Implementação)
72
+
73
+ ```python
74
+ import asyncio
75
+ import datetime
76
+ from scheduler import Scheduler
77
+
78
+ sched = Scheduler()
79
+
80
+ @sched.task(interval=datetime.timedelta(seconds=4), name="Task name")
81
+ async def example(tid: str, eid: str, name: str):
82
+ # Logic here
83
+ await asyncio.sleep(1)
84
+
85
+ async def main():
86
+ await sched.start()
87
+
88
+ if __name__ == "__main__":
89
+ asyncio.run(main())
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Diretrizes de Design
95
+
96
+ 1. **Zero Bloqueio:** Nenhuma função síncrona ou método (`time.sleep`) deve interceptar o loop principal.
97
+ 2. **Dependência Opcional:** Recursos mais pesados (como bancos de dados para persistência) devem ser plugáveis e opcionais para manter o core do motor sempre leve.
98
+ 3. **Foco na Developer Experience (DX):** A complexidade matemática e de concorrência deve sempre ficar escondida sob os panos do motor.
@@ -0,0 +1,8 @@
1
+ README.md
2
+ pyproject.toml
3
+ schedq/__init__.py
4
+ schedq/core.py
5
+ schedq.egg-info/PKG-INFO
6
+ schedq.egg-info/SOURCES.txt
7
+ schedq.egg-info/dependency_links.txt
8
+ schedq.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ schedq
schedq-0.0.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+