karrio-server 2025.5rc31__py3-none-any.whl → 2025.5rc33__py3-none-any.whl
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.
- karrio/server/VERSION +1 -1
- karrio/server/settings/apm.py +1 -1
- karrio/server/settings/base.py +87 -46
- karrio/server/settings/cache.py +66 -10
- karrio/server/settings/workers.py +118 -33
- {karrio_server-2025.5rc31.dist-info → karrio_server-2025.5rc33.dist-info}/METADATA +2 -1
- {karrio_server-2025.5rc31.dist-info → karrio_server-2025.5rc33.dist-info}/RECORD +10 -10
- {karrio_server-2025.5rc31.dist-info → karrio_server-2025.5rc33.dist-info}/WHEEL +0 -0
- {karrio_server-2025.5rc31.dist-info → karrio_server-2025.5rc33.dist-info}/entry_points.txt +0 -0
- {karrio_server-2025.5rc31.dist-info → karrio_server-2025.5rc33.dist-info}/top_level.txt +0 -0
karrio/server/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2025.
|
|
1
|
+
2025.5rc33
|
karrio/server/settings/apm.py
CHANGED
|
@@ -164,7 +164,7 @@ if OTEL_ENABLED and OTEL_EXPORTER_OTLP_ENDPOINT:
|
|
|
164
164
|
pass # Psycopg2 might not be installed
|
|
165
165
|
|
|
166
166
|
# Instrument Redis if configured
|
|
167
|
-
if config("REDIS_HOST", default=None):
|
|
167
|
+
if config("REDIS_URL", default=None) or config("REDIS_HOST", default=None):
|
|
168
168
|
try:
|
|
169
169
|
RedisInstrumentor().instrument()
|
|
170
170
|
except Exception:
|
karrio/server/settings/base.py
CHANGED
|
@@ -31,9 +31,11 @@ config = decouple.AutoConfig(search_path=Path().resolve())
|
|
|
31
31
|
|
|
32
32
|
if not config("SECRET_KEY", default=None):
|
|
33
33
|
try:
|
|
34
|
+
# Note: Using print here intentionally as logging isn't configured yet
|
|
34
35
|
print("> fallback .env.sample...")
|
|
35
36
|
config = decouple.Config(decouple.RepositoryEnv(".env.sample"))
|
|
36
37
|
except Exception as e:
|
|
38
|
+
# Note: Using print here intentionally as logging isn't configured yet
|
|
37
39
|
print(f"> error: {e}")
|
|
38
40
|
|
|
39
41
|
|
|
@@ -58,6 +60,8 @@ CORS_ALLOW_CREDENTIALS = True
|
|
|
58
60
|
CORS_ALLOW_HEADERS = list(default_headers) + [
|
|
59
61
|
"x-test-mode",
|
|
60
62
|
"x-org-id",
|
|
63
|
+
"x-tenant-id",
|
|
64
|
+
"x-request-id",
|
|
61
65
|
]
|
|
62
66
|
|
|
63
67
|
# HTTPS configuration
|
|
@@ -353,7 +357,7 @@ if config("DATABASE_URL", default=None):
|
|
|
353
357
|
DATABASES["default"].update(db_from_env)
|
|
354
358
|
|
|
355
359
|
# Configure workers database for SQLite storage when Redis is not available
|
|
356
|
-
if not config("REDIS_HOST", default=None):
|
|
360
|
+
if not config("REDIS_URL", default=None) and not config("REDIS_HOST", default=None):
|
|
357
361
|
_WORKER_DB_DIR = config("WORKER_DB_DIR", default=WORK_DIR)
|
|
358
362
|
_WORKER_DB_FILE_NAME = os.path.join(_WORKER_DB_DIR, "tasks.sqlite3")
|
|
359
363
|
DATABASES["workers"] = {
|
|
@@ -581,54 +585,91 @@ LOG_FILE_DIR = config("LOG_DIR", default=WORK_DIR)
|
|
|
581
585
|
LOG_FILE_NAME = os.path.join(LOG_FILE_DIR, "debug.log")
|
|
582
586
|
DRF_TRACKING_ADMIN_LOG_READONLY = True
|
|
583
587
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
588
|
+
# Option to use Loguru (default: True)
|
|
589
|
+
USE_LOGURU = config("USE_LOGURU", default=True, cast=bool)
|
|
590
|
+
|
|
591
|
+
if USE_LOGURU:
|
|
592
|
+
# Minimal LOGGING config - will be intercepted by Loguru
|
|
593
|
+
LOGGING = {
|
|
594
|
+
"version": 1,
|
|
595
|
+
"disable_existing_loggers": False,
|
|
596
|
+
"handlers": {
|
|
597
|
+
"console": {
|
|
598
|
+
"class": "logging.StreamHandler",
|
|
599
|
+
},
|
|
591
600
|
},
|
|
592
|
-
"
|
|
593
|
-
"format": "{levelname} {filename} {lineno} {message}",
|
|
594
|
-
"style": "{",
|
|
595
|
-
},
|
|
596
|
-
},
|
|
597
|
-
"handlers": {
|
|
598
|
-
"file": {
|
|
599
|
-
"level": "DEBUG",
|
|
600
|
-
"class": "logging.handlers.TimedRotatingFileHandler",
|
|
601
|
-
"formatter": "verbose",
|
|
602
|
-
"filename": LOG_FILE_NAME,
|
|
603
|
-
"when": "D",
|
|
604
|
-
"interval": 1,
|
|
605
|
-
"backupCount": 20,
|
|
606
|
-
},
|
|
607
|
-
"console": {
|
|
608
|
-
"class": "logging.StreamHandler",
|
|
609
|
-
"formatter": "simple",
|
|
610
|
-
},
|
|
611
|
-
},
|
|
612
|
-
"loggers": {
|
|
613
|
-
"oauth2_provider": {
|
|
614
|
-
"level": "DEBUG",
|
|
601
|
+
"root": {
|
|
615
602
|
"handlers": ["console"],
|
|
616
|
-
"
|
|
603
|
+
"level": "INFO",
|
|
617
604
|
},
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
605
|
+
}
|
|
606
|
+
else:
|
|
607
|
+
# Traditional Django logging configuration
|
|
608
|
+
LOGGING = {
|
|
609
|
+
"version": 1,
|
|
610
|
+
"disable_existing_loggers": False,
|
|
611
|
+
"formatters": {
|
|
612
|
+
"verbose": {
|
|
613
|
+
"format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
|
|
614
|
+
"style": "{",
|
|
615
|
+
},
|
|
616
|
+
"simple": {
|
|
617
|
+
"format": "{levelname} {filename} {lineno} {message}",
|
|
618
|
+
"style": "{",
|
|
619
|
+
},
|
|
622
620
|
},
|
|
623
|
-
"
|
|
624
|
-
"
|
|
625
|
-
|
|
626
|
-
|
|
621
|
+
"handlers": {
|
|
622
|
+
"file": {
|
|
623
|
+
"level": "DEBUG",
|
|
624
|
+
"class": "logging.handlers.TimedRotatingFileHandler",
|
|
625
|
+
"formatter": "verbose",
|
|
626
|
+
"filename": LOG_FILE_NAME,
|
|
627
|
+
"when": "D",
|
|
628
|
+
"interval": 1,
|
|
629
|
+
"backupCount": 20,
|
|
630
|
+
},
|
|
631
|
+
"console": {
|
|
632
|
+
"class": "logging.StreamHandler",
|
|
633
|
+
"formatter": "simple",
|
|
634
|
+
},
|
|
627
635
|
},
|
|
628
|
-
"
|
|
629
|
-
"
|
|
630
|
-
|
|
631
|
-
|
|
636
|
+
"loggers": {
|
|
637
|
+
"oauth2_provider": {
|
|
638
|
+
"level": "DEBUG",
|
|
639
|
+
"handlers": ["console"],
|
|
640
|
+
"propagate": True,
|
|
641
|
+
},
|
|
642
|
+
"django": {
|
|
643
|
+
"handlers": ["file", "console"],
|
|
644
|
+
"level": DJANGO_LOG_LEVEL,
|
|
645
|
+
"propagate": False,
|
|
646
|
+
},
|
|
647
|
+
"karrio": {
|
|
648
|
+
"handlers": ["file", "console"],
|
|
649
|
+
"level": LOG_LEVEL,
|
|
650
|
+
"propagate": False,
|
|
651
|
+
},
|
|
652
|
+
"karrio.server.core.exceptions": {
|
|
653
|
+
"handlers": ["file", "console"],
|
|
654
|
+
"level": "DEBUG",
|
|
655
|
+
"propagate": False,
|
|
656
|
+
},
|
|
632
657
|
},
|
|
633
|
-
}
|
|
634
|
-
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
# Initialize Loguru if enabled
|
|
661
|
+
if USE_LOGURU:
|
|
662
|
+
try:
|
|
663
|
+
from karrio.server.core.logging import setup_django_loguru, logger
|
|
664
|
+
|
|
665
|
+
setup_django_loguru(
|
|
666
|
+
level=LOG_LEVEL,
|
|
667
|
+
log_file=LOG_FILE_NAME,
|
|
668
|
+
intercept_django=True,
|
|
669
|
+
enqueue=True, # Thread-safe async logging
|
|
670
|
+
)
|
|
671
|
+
except ImportError as e:
|
|
672
|
+
# Note: Using print here as Loguru failed to load
|
|
673
|
+
print(f"Warning: Failed to initialize Loguru: {e}")
|
|
674
|
+
print("Falling back to standard Django logging")
|
|
675
|
+
USE_LOGURU = False
|
karrio/server/settings/cache.py
CHANGED
|
@@ -1,29 +1,85 @@
|
|
|
1
1
|
# type: ignore
|
|
2
|
+
import sys
|
|
2
3
|
from decouple import config
|
|
3
4
|
from karrio.server.settings.base import *
|
|
4
5
|
from karrio.server.settings.apm import HEALTH_CHECK_APPS
|
|
6
|
+
from karrio.server.core.logging import logger
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
CACHE_TTL = 60 * 15
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
# Check if worker is running in detached mode (separate from API server)
|
|
12
|
+
DETACHED_WORKER = config("DETACHED_WORKER", default=False, cast=bool)
|
|
13
|
+
|
|
14
|
+
# Detect if running as a worker process (via run_huey command)
|
|
15
|
+
IS_WORKER_PROCESS = any("run_huey" in arg for arg in sys.argv)
|
|
16
|
+
|
|
17
|
+
# Skip default Redis cache configuration if in worker mode
|
|
18
|
+
# Workers only need HUEY Redis, not the default Django cache
|
|
19
|
+
SKIP_DEFAULT_CACHE = DETACHED_WORKER or IS_WORKER_PROCESS
|
|
20
|
+
|
|
21
|
+
# Redis configuration - REDIS_URL takes precedence and supersedes granular env vars
|
|
22
|
+
REDIS_URL = config("REDIS_URL", default=None)
|
|
12
23
|
REDIS_PREFIX = config("REDIS_PREFIX", default="karrio")
|
|
24
|
+
REDIS_SSL = config("REDIS_SSL", default=False, cast=bool)
|
|
25
|
+
|
|
26
|
+
# Parse REDIS_URL or construct from individual parameters
|
|
27
|
+
if REDIS_URL is not None:
|
|
28
|
+
from urllib.parse import urlparse, urlunparse
|
|
29
|
+
import re
|
|
30
|
+
|
|
31
|
+
parsed = urlparse(REDIS_URL)
|
|
32
|
+
|
|
33
|
+
# Extract values from REDIS_URL (these supersede granular env vars)
|
|
34
|
+
REDIS_HOST = parsed.hostname
|
|
35
|
+
REDIS_PORT = parsed.port or 6379
|
|
36
|
+
REDIS_USERNAME = parsed.username or "default"
|
|
37
|
+
REDIS_PASSWORD = parsed.password
|
|
13
38
|
|
|
14
|
-
#
|
|
15
|
-
if
|
|
39
|
+
# Determine SSL from URL scheme (rediss:// means SSL is enabled)
|
|
40
|
+
REDIS_SCHEME = parsed.scheme if parsed.scheme in ("redis", "rediss") else "redis"
|
|
41
|
+
REDIS_SSL = REDIS_SCHEME == "rediss"
|
|
42
|
+
|
|
43
|
+
# Build connection URL with database 1 for cache
|
|
44
|
+
REDIS_AUTH = f"{REDIS_USERNAME}:{REDIS_PASSWORD}@" if REDIS_PASSWORD else ""
|
|
45
|
+
REDIS_CONNECTION_URL = f"{REDIS_SCHEME}://{REDIS_AUTH}{REDIS_HOST}:{REDIS_PORT}/1"
|
|
46
|
+
|
|
47
|
+
else:
|
|
48
|
+
# Fall back to individual parameters
|
|
49
|
+
REDIS_HOST = config("REDIS_HOST", default=None)
|
|
50
|
+
REDIS_PORT = config("REDIS_PORT", default=None)
|
|
51
|
+
REDIS_PASSWORD = config("REDIS_PASSWORD", default=None)
|
|
52
|
+
REDIS_USERNAME = config("REDIS_USERNAME", default="default")
|
|
53
|
+
|
|
54
|
+
if REDIS_HOST is not None:
|
|
55
|
+
REDIS_AUTH = f"{REDIS_USERNAME}:{REDIS_PASSWORD}@" if REDIS_PASSWORD else ""
|
|
56
|
+
REDIS_SCHEME = "rediss" if REDIS_SSL else "redis"
|
|
57
|
+
REDIS_CONNECTION_URL = (
|
|
58
|
+
f'{REDIS_SCHEME}://{REDIS_AUTH}{REDIS_HOST}:{REDIS_PORT or "6379"}/1'
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Configure Django cache if Redis is available and not in worker mode
|
|
62
|
+
if REDIS_HOST is not None and not SKIP_DEFAULT_CACHE:
|
|
16
63
|
HEALTH_CHECK_APPS += ["health_check.contrib.redis"]
|
|
17
64
|
INSTALLED_APPS += ["health_check.contrib.redis"]
|
|
18
|
-
REDIS_AUTH = f"{REDIS_USERNAME}:{REDIS_PASSWORD}@" if REDIS_PASSWORD else ""
|
|
19
65
|
|
|
20
|
-
REDIS_CONNECTION_URL = f'redis://{REDIS_AUTH}{REDIS_HOST}:{REDIS_PORT or "6379"}/1'
|
|
21
66
|
CACHES = {
|
|
22
67
|
"default": {
|
|
23
68
|
"BACKEND": "django_redis.cache.RedisCache",
|
|
24
69
|
"LOCATION": REDIS_CONNECTION_URL,
|
|
25
|
-
"OPTIONS": {
|
|
70
|
+
"OPTIONS": {
|
|
71
|
+
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
|
72
|
+
**(
|
|
73
|
+
{"CONNECTION_POOL_KWARGS": {"ssl_cert_reqs": None}}
|
|
74
|
+
if REDIS_SSL
|
|
75
|
+
else {}
|
|
76
|
+
),
|
|
77
|
+
},
|
|
26
78
|
"KEY_PREFIX": REDIS_PREFIX,
|
|
27
79
|
}
|
|
28
80
|
}
|
|
29
|
-
print(f"Redis connection initialized
|
|
81
|
+
print(f"Redis cache connection initialized")
|
|
82
|
+
elif SKIP_DEFAULT_CACHE:
|
|
83
|
+
print(
|
|
84
|
+
"Skipping default Redis cache configuration (worker mode - only HUEY Redis needed)"
|
|
85
|
+
)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# type: ignore
|
|
2
2
|
import os
|
|
3
|
+
import sys
|
|
4
|
+
import socket
|
|
3
5
|
import huey
|
|
4
6
|
import redis
|
|
5
7
|
import decouple
|
|
@@ -12,42 +14,125 @@ DEFAULT_TRACKERS_UPDATE_INTERVAL = decouple.config(
|
|
|
12
14
|
"TRACKING_PULSE", default=7200, cast=int
|
|
13
15
|
) # value is seconds. so 10800 seconds = 3 Hours
|
|
14
16
|
|
|
17
|
+
# Check if worker is running in detached mode (separate from API server)
|
|
18
|
+
DETACHED_WORKER = decouple.config("DETACHED_WORKER", default=False, cast=bool)
|
|
19
|
+
|
|
15
20
|
WORKER_IMMEDIATE_MODE = decouple.config(
|
|
16
21
|
"WORKER_IMMEDIATE_MODE", default=False, cast=bool
|
|
17
22
|
)
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
REDIS_USERNAME = decouple.config("REDIS_USERNAME", default="default")
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
# Use redis if available
|
|
26
|
-
if REDIS_HOST is not None:
|
|
27
|
-
pool = redis.ConnectionPool(
|
|
28
|
-
host=REDIS_HOST,
|
|
29
|
-
port=REDIS_PORT or "6379",
|
|
30
|
-
max_connections=20,
|
|
31
|
-
**({"password": REDIS_PASSWORD} if REDIS_PASSWORD else {}),
|
|
32
|
-
**({"username": REDIS_USERNAME} if REDIS_USERNAME else {}),
|
|
33
|
-
)
|
|
34
|
-
HUEY = huey.RedisHuey(
|
|
35
|
-
"default",
|
|
36
|
-
connection_pool=pool,
|
|
37
|
-
**({"immediate": WORKER_IMMEDIATE_MODE} if WORKER_IMMEDIATE_MODE else {}),
|
|
38
|
-
)
|
|
24
|
+
# Detect if running as a worker process (via run_huey command)
|
|
25
|
+
# Workers always need Huey configured regardless of DETACHED_WORKER setting
|
|
26
|
+
IS_WORKER_PROCESS = any("run_huey" in arg for arg in sys.argv)
|
|
39
27
|
|
|
28
|
+
# Skip Huey configuration only if:
|
|
29
|
+
# 1. Running in detached worker mode (DETACHED_WORKER=True)
|
|
30
|
+
# 2. AND not running as a worker process (IS_WORKER_PROCESS=False)
|
|
31
|
+
# This ensures workers always get Huey configured, but API servers don't when detached
|
|
32
|
+
if DETACHED_WORKER and not IS_WORKER_PROCESS:
|
|
33
|
+
# API server in detached mode - skip Huey configuration
|
|
34
|
+
HUEY = None
|
|
40
35
|
else:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
36
|
+
# Either: worker process, or API server with embedded workers
|
|
37
|
+
# Redis configuration - REDIS_URL takes precedence and supersedes granular env vars
|
|
38
|
+
REDIS_URL = decouple.config("REDIS_URL", default=None)
|
|
39
|
+
|
|
40
|
+
# Parse REDIS_URL or construct from individual parameters
|
|
41
|
+
if REDIS_URL is not None:
|
|
42
|
+
from urllib.parse import urlparse
|
|
43
|
+
|
|
44
|
+
parsed = urlparse(REDIS_URL)
|
|
45
|
+
|
|
46
|
+
# Extract values from REDIS_URL (these supersede granular env vars)
|
|
47
|
+
REDIS_HOST = parsed.hostname
|
|
48
|
+
REDIS_PORT = parsed.port or 6379
|
|
49
|
+
REDIS_USERNAME = parsed.username or "default"
|
|
50
|
+
REDIS_PASSWORD = parsed.password
|
|
51
|
+
|
|
52
|
+
# Determine SSL from URL scheme (rediss:// means SSL is enabled)
|
|
53
|
+
REDIS_SCHEME = (
|
|
54
|
+
parsed.scheme if parsed.scheme in ("redis", "rediss") else "redis"
|
|
55
|
+
)
|
|
56
|
+
REDIS_SSL = REDIS_SCHEME == "rediss"
|
|
57
|
+
|
|
58
|
+
else:
|
|
59
|
+
# Fall back to individual parameters
|
|
60
|
+
REDIS_HOST = decouple.config("REDIS_HOST", default=None)
|
|
61
|
+
REDIS_PORT = decouple.config("REDIS_PORT", default=None)
|
|
62
|
+
REDIS_PASSWORD = decouple.config("REDIS_PASSWORD", default=None)
|
|
63
|
+
REDIS_USERNAME = decouple.config("REDIS_USERNAME", default="default")
|
|
64
|
+
REDIS_SSL = decouple.config("REDIS_SSL", default=False, cast=bool)
|
|
65
|
+
|
|
66
|
+
# Configure HUEY based on available Redis configuration
|
|
67
|
+
if REDIS_HOST is not None:
|
|
68
|
+
# Calculate max connections based on environment
|
|
69
|
+
# Each worker replica needs: (workers_per_replica + 1 scheduler) connections
|
|
70
|
+
# Formula: (worker_replicas * (threads_per_worker + 1)) + api_connections + buffer
|
|
71
|
+
# Example: 100 connections = (5 replicas * (8 workers + 1 scheduler)) + 40 API + 15 buffer
|
|
72
|
+
REDIS_MAX_CONNECTIONS = decouple.config(
|
|
73
|
+
"REDIS_MAX_CONNECTIONS", default=100, cast=int
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Connection pool configuration with timeouts
|
|
77
|
+
# Use BlockingConnectionPool to wait for available connections instead of failing immediately
|
|
78
|
+
pool_kwargs = {
|
|
79
|
+
"host": REDIS_HOST,
|
|
80
|
+
"port": REDIS_PORT,
|
|
81
|
+
"max_connections": REDIS_MAX_CONNECTIONS,
|
|
82
|
+
"timeout": 20, # Wait up to 20 seconds for an available connection
|
|
83
|
+
# Timeout settings to prevent hung connections
|
|
84
|
+
"socket_timeout": 10, # Command execution timeout (seconds)
|
|
85
|
+
"socket_connect_timeout": 10, # Connection establishment timeout (seconds)
|
|
86
|
+
# Keep connections alive to prevent closure by firewalls/load balancers
|
|
87
|
+
"socket_keepalive": True,
|
|
88
|
+
# Retry on transient failures
|
|
89
|
+
"retry_on_timeout": True,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Add TCP keepalive options if available (Linux/Unix only)
|
|
93
|
+
try:
|
|
94
|
+
pool_kwargs["socket_keepalive_options"] = {
|
|
95
|
+
socket.TCP_KEEPIDLE: 60, # Start keepalive after 60s idle
|
|
96
|
+
socket.TCP_KEEPINTVL: 10, # Keepalive interval
|
|
97
|
+
socket.TCP_KEEPCNT: 3, # Keepalive probes before timeout
|
|
98
|
+
}
|
|
99
|
+
except AttributeError:
|
|
100
|
+
# TCP keepalive constants not available on this platform
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
# Add authentication if provided
|
|
104
|
+
if REDIS_PASSWORD:
|
|
105
|
+
pool_kwargs["password"] = REDIS_PASSWORD
|
|
106
|
+
if REDIS_USERNAME:
|
|
107
|
+
pool_kwargs["username"] = REDIS_USERNAME
|
|
108
|
+
|
|
109
|
+
# Add SSL/TLS configuration if enabled
|
|
110
|
+
if REDIS_SSL:
|
|
111
|
+
# Use SSLConnection class for SSL/TLS connections
|
|
112
|
+
pool_kwargs["connection_class"] = redis.SSLConnection
|
|
113
|
+
pool_kwargs["ssl_cert_reqs"] = None # For Azure Redis compatibility
|
|
114
|
+
|
|
115
|
+
# Use BlockingConnectionPool to wait for connections instead of raising errors immediately
|
|
116
|
+
pool = redis.BlockingConnectionPool(**pool_kwargs)
|
|
117
|
+
|
|
118
|
+
HUEY = huey.RedisHuey(
|
|
119
|
+
"default",
|
|
120
|
+
connection_pool=pool,
|
|
121
|
+
**({"immediate": WORKER_IMMEDIATE_MODE} if WORKER_IMMEDIATE_MODE else {}),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
else:
|
|
125
|
+
# No Redis configured, use SQLite
|
|
126
|
+
WORKER_DB_DIR = decouple.config("WORKER_DB_DIR", default=settings.WORK_DIR)
|
|
127
|
+
WORKER_DB_FILE_NAME = os.path.join(WORKER_DB_DIR, "tasks.sqlite3")
|
|
128
|
+
|
|
129
|
+
settings.DATABASES["workers"] = {
|
|
130
|
+
"NAME": WORKER_DB_FILE_NAME,
|
|
131
|
+
"ENGINE": "django.db.backends.sqlite3",
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
HUEY = huey.SqliteHuey(
|
|
135
|
+
name="default",
|
|
136
|
+
filename=WORKER_DB_FILE_NAME,
|
|
137
|
+
**({"immediate": WORKER_IMMEDIATE_MODE} if WORKER_IMMEDIATE_MODE else {}),
|
|
138
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: karrio_server
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.5rc33
|
|
4
4
|
Summary: Multi-carrier shipping API
|
|
5
5
|
Author-email: karrio <hello@karrio.io>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -42,6 +42,7 @@ Requires-Dist: opentelemetry-instrumentation-logging
|
|
|
42
42
|
Requires-Dist: opentelemetry-instrumentation-psycopg2
|
|
43
43
|
Requires-Dist: opentelemetry-instrumentation-redis
|
|
44
44
|
Requires-Dist: opentelemetry-semantic-conventions
|
|
45
|
+
Requires-Dist: loguru
|
|
45
46
|
|
|
46
47
|
# <a href="https://karrio.io" target="_blank"><img alt="Karrio" src="https://docs.karrio.io/img/logo.svg" height="50px" /></a>
|
|
47
48
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
karrio/server/VERSION,sha256=
|
|
1
|
+
karrio/server/VERSION,sha256=Jmh7RfdYs16oKOK2DMy-Yo-5r45YiB1puxKA3AUCuGc,10
|
|
2
2
|
karrio/server/__init__.py,sha256=iOEMwnlORWezdO8-2vxBIPSR37D7JGjluZ8f55vzxls,81
|
|
3
3
|
karrio/server/__main__.py,sha256=hy2-Zb2wSVe_Pu6zWZ-BhiM4rBaGZ3D16HSuhudygqg,632
|
|
4
4
|
karrio/server/asgi.py,sha256=LsZYMWo8U9zURVPdHnvUsziOhMjdCdQoD2-gMJbS2U0,462
|
|
@@ -6,13 +6,13 @@ karrio/server/workers.py,sha256=wOlWmXC7zRJV86IfbQnfUZsnCIvvWtXzFHH_EIkg1J0,179
|
|
|
6
6
|
karrio/server/wsgi.py,sha256=SpWqkEYlMsj89_znZ8p8IjH3EgTVRWRq_9eS8t64dMw,403
|
|
7
7
|
karrio/server/lib/otel_huey.py,sha256=6MP6vX6b6x6RPF2K1m8B8L8S9GK1Q3vANmLidsxh65k,5428
|
|
8
8
|
karrio/server/settings/__init__.py,sha256=iw-NBcReOnDYpnvSEBdYDfV7jC0040jYdupnmSdElec,866
|
|
9
|
-
karrio/server/settings/apm.py,sha256=
|
|
10
|
-
karrio/server/settings/base.py,sha256=
|
|
11
|
-
karrio/server/settings/cache.py,sha256=
|
|
9
|
+
karrio/server/settings/apm.py,sha256=fp9_CVzNfQ8MvNp1-WQbCILzLU3RSJeeu1vYAtdrgfs,7415
|
|
10
|
+
karrio/server/settings/base.py,sha256=UbZ4pEBEKG0mJSlNED1iU9KEpNmrZjjmwdujwnQ30fI,22285
|
|
11
|
+
karrio/server/settings/cache.py,sha256=nAHLgqynNtohxCJSMYP2RzcnBGC0ZC30KH6LlKdxgo4,3218
|
|
12
12
|
karrio/server/settings/constance.py,sha256=wKi7u-NORAPjIJMIbl3k5kPRkUA6jJJWe9kxsV3aoeA,7113
|
|
13
13
|
karrio/server/settings/debug.py,sha256=fFyK2XX47UGeK0eRNSV-9ZLaComay5QvJW0692vaH98,527
|
|
14
14
|
karrio/server/settings/email.py,sha256=bHBLKM_v3HTkmjrz_Msdj_Z7_kMzAb7i6pvJCZuzu1E,1403
|
|
15
|
-
karrio/server/settings/workers.py,sha256=
|
|
15
|
+
karrio/server/settings/workers.py,sha256=Ey59-TQ2odW-e15Mf2OZjQSLzX3jNCnWMC7dy-T2A3o,5755
|
|
16
16
|
karrio/server/static/extra/branding/android-chrome-192x192.png,sha256=qSwEKKBtk4udSHb0OWGC5-jfkP5cVpULDD1Cdkuk8PU,7005
|
|
17
17
|
karrio/server/static/extra/branding/android-chrome-512x512.png,sha256=YFwVPnPChO30tTuyrwSc_z548H7C6OFXh4CCu2krvHA,21062
|
|
18
18
|
karrio/server/static/extra/branding/favicon-16x16.png,sha256=wkELpij29bIvvKr5sDcjfNeYvj7i0yk-__bJbZckEK8,1085
|
|
@@ -73,8 +73,8 @@ karrio/server/templates/admin/base_site.html,sha256=kbcdvehXZ1EHaw07JL7fSZmjrnVM
|
|
|
73
73
|
karrio/server/templates/openapi/openapi.html,sha256=3ApCZ5pE6Wjv7CJllVbqD2WiDQuLy-BFS-IIHurXhBY,1133
|
|
74
74
|
karrio/server/urls/__init__.py,sha256=Ah-XqaqRsfecQgCGRHjxmXe8O7a0avq5ocU90tkVwQI,1998
|
|
75
75
|
karrio/server/urls/jwt.py,sha256=QN2L-EpUEQCF2UGYPu_VVlA49Fc0BtcY7Ov3-xpp7_U,6772
|
|
76
|
-
karrio_server-2025.
|
|
77
|
-
karrio_server-2025.
|
|
78
|
-
karrio_server-2025.
|
|
79
|
-
karrio_server-2025.
|
|
80
|
-
karrio_server-2025.
|
|
76
|
+
karrio_server-2025.5rc33.dist-info/METADATA,sha256=dCp9nxE9T_UWaj-PjNugMeqMiHG_7Udgr8PvKnfPioA,4305
|
|
77
|
+
karrio_server-2025.5rc33.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
78
|
+
karrio_server-2025.5rc33.dist-info/entry_points.txt,sha256=c2eftt6MpJjyp0OFv1OmO9nUYSDemt9fGq_RDdvpGLw,55
|
|
79
|
+
karrio_server-2025.5rc33.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
|
|
80
|
+
karrio_server-2025.5rc33.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|