fred-oss 0.7.0__tar.gz → 0.8.0__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.
- {fred_oss-0.7.0/src/main/fred_oss.egg-info → fred_oss-0.8.0}/PKG-INFO +2 -1
- {fred_oss-0.7.0 → fred_oss-0.8.0}/requirements.txt +2 -0
- fred_oss-0.8.0/src/main/fred/version +1 -0
- fred_oss-0.8.0/src/main/fred/worker/runner/__init__.py +11 -0
- fred_oss-0.8.0/src/main/fred/worker/runner/handler.py +136 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0/src/main/fred_oss.egg-info}/PKG-INFO +2 -1
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred_oss.egg-info/SOURCES.txt +2 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred_oss.egg-info/requires.txt +1 -0
- fred_oss-0.7.0/src/main/fred/version +0 -1
- {fred_oss-0.7.0 → fred_oss-0.8.0}/MANIFEST.in +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/NOTICE.txt +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/README.md +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/setup.cfg +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/setup.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/cli/__init__.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/cli/__main__.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/cli/interface.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/cli/main.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/__init__.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/cli_ext.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/runtime.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/runtimes/__init__.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/runtimes/scanner.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/runtimes/sync.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/wrappers/__init__.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/wrappers/dbutils.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/runpod/__init__.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/runpod/cli_ext.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/runpod/helper.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/maturity.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/settings.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/utils/__init__.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/utils/dateops.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/utils/runtime.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/version.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/worker/__init__.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/worker/interface.py +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred_oss.egg-info/dependency_links.txt +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred_oss.egg-info/entry_points.txt +0 -0
- {fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred_oss.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fred-oss
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: FREDOSS
|
|
5
5
|
Home-page: https://fred.fahera.mx
|
|
6
6
|
Author: Fahera Research, Education, and Development
|
|
@@ -10,6 +10,7 @@ Description-Content-Type: text/markdown
|
|
|
10
10
|
License-File: NOTICE.txt
|
|
11
11
|
Requires-Dist: fire==0.7.1
|
|
12
12
|
Requires-Dist: psutil==7.0.0
|
|
13
|
+
Requires-Dist: redis==6.4.0
|
|
13
14
|
Dynamic: author
|
|
14
15
|
Dynamic: author-email
|
|
15
16
|
Dynamic: description
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.8.0
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from fred.maturity import Maturity, MaturityLevel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module_maturity = Maturity(
|
|
5
|
+
level=MaturityLevel.ALPHA,
|
|
6
|
+
reference=__name__,
|
|
7
|
+
message=(
|
|
8
|
+
"Fred-Worker Redis Runners implementation is in early development "
|
|
9
|
+
"and therefore currently with incomplete and unstable features."
|
|
10
|
+
)
|
|
11
|
+
)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
import json
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from fred.utils.dateops import datetime_utcnow
|
|
6
|
+
from fred.worker.interface import HandlerInterface
|
|
7
|
+
from fred.settings import (
|
|
8
|
+
get_environ_variable,
|
|
9
|
+
logger_manager,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from redis import Redis
|
|
13
|
+
|
|
14
|
+
logger = logger_manager.get_logger(name=__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True, slots=False)
|
|
18
|
+
class RunnerHandler(HandlerInterface):
|
|
19
|
+
|
|
20
|
+
def __post_init__(self):
|
|
21
|
+
super().__post_init__()
|
|
22
|
+
logger.info("Runpod Handler initialized using Fred-Worker interface.")
|
|
23
|
+
|
|
24
|
+
def handler(self, payload: dict) -> dict:
|
|
25
|
+
# TODO: Breakdown the handler logic into smaller methods for better readability and testing
|
|
26
|
+
# E.g., loop method, process item method, signal handling method, etc.
|
|
27
|
+
lifespan = payload.get("lifetime", 3600) # Default to 1 hour if not specified
|
|
28
|
+
timeout = payload.get("timeout", 30) # Default to 30 seconds if not specified
|
|
29
|
+
# Get Redis connection details from payload or environment variables
|
|
30
|
+
redis_configs = payload.pop(
|
|
31
|
+
"redis_configs",
|
|
32
|
+
{
|
|
33
|
+
"host": get_environ_variable(name="REDIS_HOST", default="localhost"),
|
|
34
|
+
"port": int(get_environ_variable(name="REDIS_PORT", default=6379)),
|
|
35
|
+
"db": int(get_environ_variable(name="REDIS_DB", default=0)),
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
# Connect to Redis
|
|
39
|
+
redis = Redis(**redis_configs)
|
|
40
|
+
req_queue = payload.pop("redis_request_queue", None) or get_environ_variable(name="FRD_RUNNER_REQUEST_QUEUE", default=None) or (
|
|
41
|
+
logger.warning("Redis request queue not specified; defaulting to: 'req:demo'") or "req:demo"
|
|
42
|
+
)
|
|
43
|
+
res_queue = payload.pop("redis_response_queue", None) or get_environ_variable(name="FRD_RUNNER_RESPONSE_QUEUE", default=None) or (
|
|
44
|
+
logger.warning("Redis response queue not specified; defaulting to: None (not using response queue)") or None
|
|
45
|
+
)
|
|
46
|
+
# Handoff to target handler (i.e., runner)
|
|
47
|
+
runner_configs = payload.pop("runner_configs")
|
|
48
|
+
runner_id = runner_configs.pop("id", str(uuid.uuid4()))
|
|
49
|
+
runner = HandlerInterface.find_handler(**runner_configs)
|
|
50
|
+
logger.info(f"Runpod Redis Handler started with runner '{runner_id}' listening to Redis queue: '{req_queue}'")
|
|
51
|
+
redis.set(f"runner_status:{runner_id}", "RUNNING")
|
|
52
|
+
redis.set(f"runner_created_at:{runner_id}", datetime_utcnow().isoformat())
|
|
53
|
+
# Main runner loop to process items from Redis queue
|
|
54
|
+
# TODO: Can we make this main-loop concurrent with threads or async?
|
|
55
|
+
# TODO: Consider collecting metrics (e.g., processing time per item, total items processed, errors, etc.) and stats
|
|
56
|
+
start_time = datetime_utcnow()
|
|
57
|
+
last_processed_time = datetime_utcnow()
|
|
58
|
+
while (elapsed_seconds := (datetime_utcnow() - start_time).total_seconds()):
|
|
59
|
+
if elapsed_seconds > lifespan:
|
|
60
|
+
logger.info("Lifespan exceeded; exiting runner loop.")
|
|
61
|
+
break
|
|
62
|
+
if (idle_seconds := (datetime_utcnow() - last_processed_time).total_seconds()) > timeout:
|
|
63
|
+
logger.info(f"Idle time ({idle_seconds}) exceeded timeout ({timeout}); exiting runner loop.")
|
|
64
|
+
break
|
|
65
|
+
# Fetch item from Redis queue
|
|
66
|
+
try:
|
|
67
|
+
item_raw = redis.rpop(req_queue)
|
|
68
|
+
except Exception as e:
|
|
69
|
+
logger.error(f"Error fetching item from Redis queue '{req_queue}': {e}")
|
|
70
|
+
continue
|
|
71
|
+
# If no item, iterate again
|
|
72
|
+
if not item_raw:
|
|
73
|
+
continue
|
|
74
|
+
try:
|
|
75
|
+
# Handle special signals
|
|
76
|
+
match (item_str := item_raw.decode("utf-8")):
|
|
77
|
+
case "STOP" | "SHUTDOWN" | "TERMINATE":
|
|
78
|
+
logger.info("Received STOP signal; exiting runner loop.")
|
|
79
|
+
break
|
|
80
|
+
case "PING":
|
|
81
|
+
logger.info("Received PING signal; continuing.")
|
|
82
|
+
last_processed_time = datetime_utcnow()
|
|
83
|
+
continue
|
|
84
|
+
case _:
|
|
85
|
+
pass
|
|
86
|
+
# Parse item payload and extract item_id
|
|
87
|
+
item_payload = json.loads(item_str)
|
|
88
|
+
item_id = item_payload.pop("item_id") or (
|
|
89
|
+
logger.warning("No item_id provided in payload; generating a new one using UUID5.")
|
|
90
|
+
or str(uuid.uuid5(uuid.NAMESPACE_OID, item_str))
|
|
91
|
+
)
|
|
92
|
+
except Exception as e:
|
|
93
|
+
logger.error(f"Error decoding or parsing item from Redis: {e}")
|
|
94
|
+
continue
|
|
95
|
+
logger.info(f"Processing item with ID: {item_id}")
|
|
96
|
+
redis.set(f"item_status:{item_id}", "IN_PROGRESS")
|
|
97
|
+
try:
|
|
98
|
+
out_payload = runner.run(
|
|
99
|
+
event={
|
|
100
|
+
"id": item_id,
|
|
101
|
+
"input": item_payload
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
out_str = json.dumps(out_payload) if isinstance(out_payload, dict) else str(out_payload)
|
|
105
|
+
redis.set(f"item_status:{item_id}", "COMPLETED")
|
|
106
|
+
# TODO: Consider adding a TTL to the result keys (e.g., 24 hours)
|
|
107
|
+
redis.set(f"item_output:{item_id}", out_str)
|
|
108
|
+
if res_queue:
|
|
109
|
+
redis.lpush(res_queue, out_str)
|
|
110
|
+
except Exception as e:
|
|
111
|
+
logger.error(f"Error processing item with ID {item_id}: {e}")
|
|
112
|
+
redis.set(f"item_status:{item_id}", "FAILED")
|
|
113
|
+
redis.set(f"item_output:{item_id}", str(e))
|
|
114
|
+
continue
|
|
115
|
+
logger.info(f"Processed item with ID: {item_id}")
|
|
116
|
+
last_processed_time = datetime_utcnow()
|
|
117
|
+
redis.set(f"runner_status:{runner_id}", "STOPPED")
|
|
118
|
+
pending_requests = redis.llen(req_queue)
|
|
119
|
+
if pending_requests:
|
|
120
|
+
logger.warning(f"Runner '{runner_id}' stopped with {pending_requests} pending items still in the queue '{req_queue}'.")
|
|
121
|
+
# TODO: Consider adding logic (optional/configurable) to spin up a new runner to handle pending items or notify runner-manager
|
|
122
|
+
else:
|
|
123
|
+
logger.info("Runner stopped with no pending items in the queue.")
|
|
124
|
+
return {
|
|
125
|
+
"status": "completed",
|
|
126
|
+
"runner_id": runner_id,
|
|
127
|
+
"processed_at": datetime_utcnow().isoformat(),
|
|
128
|
+
"total_elapsed_seconds": (datetime_utcnow() - start_time).total_seconds(),
|
|
129
|
+
"last_processed_at": last_processed_time.isoformat(),
|
|
130
|
+
"idle_seconds": (datetime_utcnow() - last_processed_time).total_seconds(),
|
|
131
|
+
"pending_requests": pending_requests,
|
|
132
|
+
"request_queue": req_queue,
|
|
133
|
+
"response_queue": res_queue,
|
|
134
|
+
"lifespan_seconds": lifespan,
|
|
135
|
+
"timeout_seconds": timeout,
|
|
136
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fred-oss
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: FREDOSS
|
|
5
5
|
Home-page: https://fred.fahera.mx
|
|
6
6
|
Author: Fahera Research, Education, and Development
|
|
@@ -10,6 +10,7 @@ Description-Content-Type: text/markdown
|
|
|
10
10
|
License-File: NOTICE.txt
|
|
11
11
|
Requires-Dist: fire==0.7.1
|
|
12
12
|
Requires-Dist: psutil==7.0.0
|
|
13
|
+
Requires-Dist: redis==6.4.0
|
|
13
14
|
Dynamic: author
|
|
14
15
|
Dynamic: author-email
|
|
15
16
|
Dynamic: description
|
|
@@ -27,6 +27,8 @@ src/main/fred/utils/dateops.py
|
|
|
27
27
|
src/main/fred/utils/runtime.py
|
|
28
28
|
src/main/fred/worker/__init__.py
|
|
29
29
|
src/main/fred/worker/interface.py
|
|
30
|
+
src/main/fred/worker/runner/__init__.py
|
|
31
|
+
src/main/fred/worker/runner/handler.py
|
|
30
32
|
src/main/fred_oss.egg-info/PKG-INFO
|
|
31
33
|
src/main/fred_oss.egg-info/SOURCES.txt
|
|
32
34
|
src/main/fred_oss.egg-info/dependency_links.txt
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.7.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/runtimes/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fred_oss-0.7.0 → fred_oss-0.8.0}/src/main/fred/integrations/databricks/wrappers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|