Initial commit

This commit is contained in:
2026-07-18 12:00:33 +05:30
commit caac8413e9
83 changed files with 10262 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: core-config
namespace: core
labels:
app.kubernetes.io/name: core-config
app.kubernetes.io/part-of: core
data:
NATS_URL: "nats://66.116.226.161:4222"
LOG_LEVEL: "info"
ALLOWED_ORIGINS: "http://localhost:3001,http://localhost:3000,https://queue.workolik.com,https://console.nearlexpress.com"
EXTERNAL_BASE_URL: "https://jupiter.nearle.app"
WORKER_CONCURRENCY: "10"
RETRY_ATTEMPTS: "5"
RETRY_DELAY_SECONDS: "5"
NATS_STREAM: "EVENTS"
NATS_SUBJECT: "api.>"
NATS_CONSUMER: "worker_consumer"

View File

@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: core
labels:
name: core

View File

@@ -0,0 +1,25 @@
apiVersion: v1
kind: Secret
metadata:
name: nats-credentials
namespace: core
labels:
app.kubernetes.io/name: nats-credentials
app.kubernetes.io/part-of: core
type: Opaque
stringData:
username: admin
password: package@321#
---
apiVersion: v1
kind: Secret
metadata:
name: external-endpoint-secrets
namespace: core
labels:
app.kubernetes.io/name: external-endpoint-secrets
app.kubernetes.io/part-of: core
type: Opaque
stringData:
api_key: "" # Add your API key securely

View File

@@ -0,0 +1,76 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: queue-ingress
namespace: alaska
annotations:
traefik.ingress.kubernetes.io/router.middlewares: alaska-common-cors@kubernetescrd
traefik.ingress.kubernetes.io/router.tls: "true"
# Cert resolver if you have it configured globally in Traefik (usually k3s-provided)
# traefik.ingress.kubernetes.io/router.tls.certresolver: "letsencrypt"
spec:
rules:
- host: queue.workolik.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: deliveries-service
port:
number: 8000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nearle-ingress
namespace: nearle
annotations:
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
rules:
- host: jupiter.nearle.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jupiter-cors-proxy
port:
number: 80
- host: fiesta.nearle.app
http:
paths:
- path: /live/api/v1/mob/orders/createorder
pathType: Prefix
backend:
service:
name: fiesta
port:
number: 8000
- path: /live/api/v1/web/products/create
pathType: Prefix
backend:
service:
name: fiesta
port:
number: 8000
- path: /
pathType: Prefix
backend:
service:
name: fiesta
port:
number: 80
- host: atlantis.nearle.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: atlantis
port:
number: 80

View File

@@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: core
resources:
- core-namespace.yaml
- core-secrets.yaml
- core-config.yaml
- worker-script.yaml
- workers.yaml
- worker-pdb.yaml

View File

@@ -0,0 +1,41 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: common-cors
namespace: alaska
spec:
headers:
accessControlAllowMethods:
- GET
- POST
- PUT
- PATCH
- DELETE
- OPTIONS
accessControlAllowOriginList:
- "*"
accessControlAllowHeaders:
- "*"
accessControlMaxAge: 600
addVaryHeader: true
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: common-cors
namespace: nearle
spec:
headers:
accessControlAllowMethods:
- GET
- POST
- PUT
- PATCH
- DELETE
- OPTIONS
accessControlAllowOriginList:
- "*"
accessControlAllowHeaders:
- "*"
accessControlMaxAge: 600
addVaryHeader: true

View File

@@ -0,0 +1,13 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: worker-pdb
namespace: core
labels:
app.kubernetes.io/name: worker
app.kubernetes.io/part-of: core
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/name: worker

View File

@@ -0,0 +1,261 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: worker-script
namespace: core
data:
worker.py: |
#!/usr/bin/env python3
"""
NATS Worker - "New Idea" Implementation
- Single Domain per Worker (Stream + Consumer)
- Persistent HTTP Session (Connection Pooling)
- JetStream Native Retries (NAK)
- No internal retry loops
"""
import os
import json
import asyncio
import aiohttp
import nats
from nats.errors import TimeoutError as NatsTimeoutError
from prometheus_client import Counter, Histogram, Gauge, start_http_server
import signal
import sys
from typing import Any, Dict, List, Union, Tuple
# Prometheus metrics
messages_processed = Counter('worker_messages_processed_total', 'Total messages processed', ['status', 'endpoint'])
message_duration = Histogram('worker_message_duration_seconds', 'Message processing duration', ['endpoint'])
messages_in_flight = Gauge('worker_messages_in_flight', 'Messages currently being processed')
# Configuration
NATS_URL = os.getenv("NATS_URL", "nats://nats-server:4222")
NATS_USER = os.getenv("NATS_USER", "admin")
NATS_PASSWORD = os.getenv("NATS_PASSWORD", "package@321#")
# Domain Configuration (Env Vars from Deployment)
NATS_STREAM = os.getenv("NATS_STREAM", "ORDERS")
NATS_CONSUMER = os.getenv("NATS_CONSUMER", "orders-worker")
# Supports comma-separated subjects: "api.v1.orders.*,api.v2.orders.*"
FILTER_SUBJECTS = os.getenv("FILTER_SUBJECT", "api.v1.mob.orders.*").split(",")
WORKER_CONCURRENCY = int(os.getenv("WORKER_CONCURRENCY", "10"))
BASE_URL = os.getenv("EXTERNAL_BASE_URL", "https://jupiter.nearle.app")
# Endpoint mapping is still useful for constructing the target URL
ENDPOINT_MAPPING = {
"/live/api/v1/deliveries/createdeliveries": f"{BASE_URL}/live/api/v1/deliveries/createdeliveries",
"/live/api/v1/deliveries/updatedelivery": f"{BASE_URL}/live/api/v1/deliveries/updatedelivery",
"/live/api/v2/partners/createriderlog": f"{BASE_URL}/live/api/v2/partners/createriderlog",
"/live/api/v2/deliveries/createdeliverylog": f"{BASE_URL}/live/api/v2/deliveries/createdeliverylog",
"/live/api/v2/partners/createbreaklog": f"{BASE_URL}/live/api/v2/partners/createbreaklog",
"/live/api/v2/partners/updatebreaklog": f"{BASE_URL}/live/api/v2/partners/updatebreaklog",
"/live/api/v1/mob/orders/createorder": f"{BASE_URL}/live/api/v1/mob/orders/createorder",
"/live/api/v1/web/products/create": f"{BASE_URL}/live/api/v1/web/products/create",
"/live/api/v1/mob/customers/login": f"{BASE_URL}/live/api/v1/mob/customers/login",
"/live/api/v1/mob/customers/create": f"{BASE_URL}/live/api/v1/mob/customers/create",
}
# Global State
nc = None
js = None
session: aiohttp.ClientSession = None
running = True
semaphore = None # Initialized in main
def signal_handler(sig, frame):
global running
print("\n?? Shutdown signal received...")
running = False
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
async def forward_to_external(endpoint: str, payload: dict, api_key: str = None, method: str = "POST") -> tuple[str, Any]:
"""
Forward to external API using global session.
Returns (status_code, response_data).
Does NOT retry internally.
"""
external_url = ENDPOINT_MAPPING.get(endpoint)
if not external_url:
print(f"?? Unknown endpoint: {endpoint}, dropping.")
return "DROP", None
headers = {"Content-Type": "application/json"}
if api_key:
headers["Authorization"] = f"Bearer {api_key}"
data_to_forward = payload.get("data", payload)
# Payload Normalization for logs
if endpoint == "/live/api/v2/deliveries/createdeliverylog":
if isinstance(data_to_forward, dict):
data_to_forward = [data_to_forward]
elif not isinstance(data_to_forward, list):
data_to_forward = [data_to_forward]
http_method = method.upper() if method else "POST"
try:
# We use the global 'session' here
async with session.request(
method=http_method,
url=external_url,
json=data_to_forward if http_method != "GET" else None,
params=data_to_forward if http_method == "GET" else None,
headers=headers,
timeout=aiohttp.ClientTimeout(total=30)
) as response:
body = None
try:
body = await response.json()
except:
body = await response.text()
if 200 <= response.status < 300:
return "OK", body
elif response.status >= 500:
print(f"?? Server Error {response.status} from {endpoint}: {body}")
return "RETRY", body
else:
print(f"?? Client Error {response.status} from {endpoint}: {body}")
return "DROP", body # 4xx errors should generally not be retried infinitely
except asyncio.TimeoutError:
print(f"?? Timeout calling {endpoint}")
return "RETRY", None
except Exception as e:
print(f"?? Network/Client Error calling {endpoint}: {e}")
return "RETRY", None
async def process_message(msg):
async with semaphore:
messages_in_flight.inc()
start_time = asyncio.get_event_loop().time()
endpoint = "unknown"
try:
payload = json.loads(msg.data.decode())
endpoint = payload.get("endpoint", payload.get("original_path", "unknown"))
http_method = payload.get("method", "POST")
print(f"?? Processing {endpoint}")
api_key = os.getenv("EXTERNAL_ENDPOINT_API_KEY", "")
# Single attempt
status, response_data = await forward_to_external(endpoint, payload, api_key, http_method)
if status == "OK":
await msg.ack()
messages_processed.labels(status="success", endpoint=endpoint).inc()
# Request-Reply Logic
if msg.reply:
reply_payload = json.dumps(response_data) if isinstance(response_data, (dict, list)) else str(response_data)
await nc.publish(msg.reply, reply_payload.encode())
elif status == "DROP":
# Unrecoverable error or unknown endpoint
await msg.term() # Terminate stops redelivery
messages_processed.labels(status="dropped", endpoint=endpoint).inc()
else: # RETRY
# Let JetStream handle backoff
await msg.nak(delay=2) # Custom delay before redelivery if desired, or just nak()
messages_processed.labels(status="retried", endpoint=endpoint).inc()
except json.JSONDecodeError:
print("?? Invalid JSON, terminating message")
await msg.term()
except Exception as e:
print(f"? Critical Worker Error: {e}")
await msg.nak()
finally:
messages_in_flight.dec()
duration = asyncio.get_event_loop().time() - start_time
message_duration.labels(endpoint=endpoint).observe(duration)
async def main():
global nc, js, session, semaphore
print(f"?? Starting Worker for Domain: {NATS_CONSUMER}")
print(f"?? Stream: {NATS_STREAM}, Subjects: {FILTER_SUBJECTS}")
print(f"?? Concurrency: {WORKER_CONCURRENCY}")
semaphore = asyncio.Semaphore(WORKER_CONCURRENCY)
session = aiohttp.ClientSession()
try:
nc = await nats.connect(
servers=[NATS_URL],
user=NATS_USER,
password=NATS_PASSWORD,
reconnect_time_wait=2,
max_reconnect_attempts=-1
)
js = nc.jetstream()
print("? Connected to NATS JetStream")
# Create Pull Subscriptions for each filter subject
# All sharing the same Consumer Name ensuring load balancing if multiple pods run this
subs = []
for subject in FILTER_SUBJECTS:
subject = subject.strip()
if not subject: continue
# FIX: On WorkQueue streams, we cannot reuse the same durable name for different filters
# We append a sanitized version of the subject to ensure uniqueness per filter
clean_subject_suffix = subject.replace(".", "_").replace("*", "all").replace(">", "all")
durable_name = f"{NATS_CONSUMER}_{clean_subject_suffix}"
print(f"?? Subscribing to {subject} on durable consumer '{durable_name}'")
try:
sub = await js.pull_subscribe(
subject,
durable=durable_name,
stream=NATS_STREAM
)
subs.append(sub)
except Exception as e:
print(f"? Failed to subscribe to {subject}: {e}")
if not subs:
print("? No active subscriptions!")
return
start_http_server(9090)
print("?? Metrics on :9090")
while running:
# Poll all subscriptions
for sub in subs:
try:
# Batch size 10, short timeout to keep loop responsive
msgs = await sub.fetch(10, timeout=0.5)
for m in msgs:
asyncio.create_task(process_message(m))
except NatsTimeoutError:
pass
except Exception as e:
print(f"?? Fetch Error: {e}")
await asyncio.sleep(1)
# Small sleep to prevent tight loop if no messages
# await asyncio.sleep(0.01)
except Exception as e:
print(f"?? Fatal Error: {e}")
finally:
if session:
await session.close()
if nc:
await nc.close()
print("?? Worker Shutdown")
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -0,0 +1,129 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: worker
namespace: core
labels:
app.kubernetes.io/name: worker
app.kubernetes.io/instance: worker-primary
app.kubernetes.io/part-of: core
app.kubernetes.io/component: worker
spec:
serviceName: "worker" # Required for StatefulSet
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: worker
app.kubernetes.io/instance: worker-primary
template:
metadata:
labels:
app.kubernetes.io/name: worker
app.kubernetes.io/instance: worker-primary
app.kubernetes.io/part-of: core
app.kubernetes.io/component: worker
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 2000
tolerations:
- key: dedicated
operator: Equal
value: workers
effect: NoSchedule
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.workolik/worker
operator: In
values:
- "true"
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- worker
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: worker
containers:
- name: worker
image: workolik360/nats-worker:v1.1.0
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
capabilities:
drop:
- ALL
ports:
- containerPort: 9090
name: metrics
command: ["python3", "-u", "/scripts/worker.py"]
volumeMounts:
- name: worker-script-vol
mountPath: /scripts
envFrom:
- configMapRef:
name: core-config
env:
- name: NATS_USER
valueFrom:
secretKeyRef:
name: nats-credentials
key: username
- name: NATS_PASSWORD
valueFrom:
secretKeyRef:
name: nats-credentials
key: password
- name: EXTERNAL_ENDPOINT_API_KEY
valueFrom:
secretKeyRef:
name: external-endpoint-secrets
key: api_key
optional: true
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /metrics
port: 9090
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /metrics
port: 9090
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
volumes:
- name: worker-script-vol
configMap:
name: worker-script

542
manifests/core/workers.yaml Normal file
View File

@@ -0,0 +1,542 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: worker-orders
namespace: core
labels:
app.kubernetes.io/name: worker-orders
app.kubernetes.io/component: worker
spec:
serviceName: "worker-orders"
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: worker-orders
template:
metadata:
labels:
app.kubernetes.io/name: worker-orders
app.kubernetes.io/component: worker
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
tolerations:
- key: dedicated
operator: Equal
value: workers
effect: NoSchedule
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.workolik/worker
operator: In
values:
- "true"
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- worker-orders
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: worker-orders
containers:
- name: worker
image: workolik360/nats-worker:v1.1.0
imagePullPolicy: IfNotPresent
command: ["python3", "-u", "/scripts/worker.py"]
volumeMounts:
- name: worker-script-vol
mountPath: /scripts
envFrom:
- configMapRef:
name: core-config
env:
- name: NATS_STREAM
value: "ORDERS"
- name: NATS_CONSUMER
value: "orders-worker"
- name: FILTER_SUBJECT
value: "api.v1.mob.orders.createorder"
- name: WORKER_CONCURRENCY
value: "20"
- name: NATS_USER
valueFrom:
secretKeyRef:
name: nats-credentials
key: username
- name: NATS_PASSWORD
valueFrom:
secretKeyRef:
name: nats-credentials
key: password
- name: EXTERNAL_ENDPOINT_API_KEY
valueFrom:
secretKeyRef:
name: external-endpoint-secrets
key: api_key
optional: true
- name: EXTERNAL_BASE_URL
value: "http://10.43.229.168"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
ports:
- containerPort: 9090
name: metrics
volumes:
- name: worker-script-vol
configMap:
name: worker-script
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: worker-deliveries
namespace: core
labels:
app.kubernetes.io/name: worker-deliveries
app.kubernetes.io/component: worker
spec:
serviceName: "worker-deliveries"
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: worker-deliveries
template:
metadata:
labels:
app.kubernetes.io/name: worker-deliveries
app.kubernetes.io/component: worker
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
tolerations:
- key: dedicated
operator: Equal
value: workers
effect: NoSchedule
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.workolik/worker
operator: In
values:
- "true"
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- worker-deliveries
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: worker-deliveries
containers:
- name: worker
image: workolik360/nats-worker:v1.1.0
imagePullPolicy: IfNotPresent
command: ["python3", "-u", "/scripts/worker.py"]
volumeMounts:
- name: worker-script-vol
mountPath: /scripts
envFrom:
- configMapRef:
name: core-config
env:
- name: NATS_STREAM
value: "DELIVERIES"
- name: NATS_CONSUMER
value: "deliveries-worker"
- name: FILTER_SUBJECT
value: "api.v1.deliveries.createdeliveries,api.v1.deliveries.updatedelivery,api.v2.deliveries.createdeliverylog"
- name: WORKER_CONCURRENCY
value: "10"
- name: NATS_USER
valueFrom:
secretKeyRef:
name: nats-credentials
key: username
- name: NATS_PASSWORD
valueFrom:
secretKeyRef:
name: nats-credentials
key: password
- name: EXTERNAL_BASE_URL
value: "http://10.43.224.63"
resources:
requests:
memory: "128Mi"
cpu: "80m"
limits:
memory: "256Mi"
cpu: "400m"
ports:
- containerPort: 9090
name: metrics
volumes:
- name: worker-script-vol
configMap:
name: worker-script
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: worker-customers
namespace: core
labels:
app.kubernetes.io/name: worker-customers
app.kubernetes.io/component: worker
spec:
serviceName: "worker-customers"
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: worker-customers
template:
metadata:
labels:
app.kubernetes.io/name: worker-customers
app.kubernetes.io/component: worker
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
tolerations:
- key: dedicated
operator: Equal
value: workers
effect: NoSchedule
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.workolik/worker
operator: In
values:
- "true"
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- worker-customers
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: worker-customers
containers:
- name: worker
image: workolik360/nats-worker:v1.1.0
imagePullPolicy: IfNotPresent
command: ["python3", "-u", "/scripts/worker.py"]
volumeMounts:
- name: worker-script-vol
mountPath: /scripts
envFrom:
- configMapRef:
name: core-config
env:
- name: NATS_STREAM
value: "CUSTOMERS"
- name: NATS_CONSUMER
value: "customers-worker"
- name: FILTER_SUBJECT
value: "api.v1.mob.customers.login,api.v1.mob.customers.create"
- name: WORKER_CONCURRENCY
value: "30"
- name: NATS_USER
valueFrom:
secretKeyRef:
name: nats-credentials
key: username
- name: NATS_PASSWORD
valueFrom:
secretKeyRef:
name: nats-credentials
key: password
- name: EXTERNAL_ENDPOINT_API_KEY
valueFrom:
secretKeyRef:
name: external-endpoint-secrets
key: api_key
optional: true
- name: EXTERNAL_BASE_URL
value: "http://10.43.229.168"
resources:
requests:
memory: "128Mi"
cpu: "60m"
limits:
memory: "256Mi"
cpu: "300m"
ports:
- containerPort: 9090
name: metrics
volumes:
- name: worker-script-vol
configMap:
name: worker-script
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: worker-rider-logs
namespace: core
labels:
app.kubernetes.io/name: worker-rider-logs
app.kubernetes.io/component: worker
spec:
serviceName: "worker-rider-logs"
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: worker-rider-logs
template:
metadata:
labels:
app.kubernetes.io/name: worker-rider-logs
app.kubernetes.io/component: worker
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
tolerations:
- key: dedicated
operator: Equal
value: workers
effect: NoSchedule
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.workolik/worker
operator: In
values:
- "true"
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- worker-rider-logs
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: worker-rider-logs
containers:
- name: worker
image: workolik360/nats-worker:v1.1.0
imagePullPolicy: IfNotPresent
command: ["python3", "-u", "/scripts/worker.py"]
volumeMounts:
- name: worker-script-vol
mountPath: /scripts
envFrom:
- configMapRef:
name: core-config
env:
- name: NATS_STREAM
value: "RIDER"
- name: NATS_CONSUMER
value: "rider-logs-worker"
- name: FILTER_SUBJECT
value: "api.v2.partners.createriderlog,api.v2.partners.createbreaklog,api.v2.partners.updatebreaklog"
- name: WORKER_CONCURRENCY
value: "10"
- name: NATS_USER
valueFrom:
secretKeyRef:
name: nats-credentials
key: username
- name: NATS_PASSWORD
valueFrom:
secretKeyRef:
name: nats-credentials
key: password
- name: EXTERNAL_ENDPOINT_API_KEY
valueFrom:
secretKeyRef:
name: external-endpoint-secrets
key: api_key
optional: true
- name: EXTERNAL_BASE_URL
value: "http://10.43.224.63"
resources:
requests:
memory: "128Mi"
cpu: "40m"
limits:
memory: "128Mi"
cpu: "200m"
ports:
- containerPort: 9090
name: metrics
volumes:
- name: worker-script-vol
configMap:
name: worker-script
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: worker-products
namespace: core
labels:
app.kubernetes.io/name: worker-products
app.kubernetes.io/component: worker
spec:
serviceName: "worker-products"
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: worker-products
template:
metadata:
labels:
app.kubernetes.io/name: worker-products
app.kubernetes.io/component: worker
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
tolerations:
- key: dedicated
operator: Equal
value: workers
effect: NoSchedule
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.workolik/worker
operator: In
values:
- "true"
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- worker-products
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: worker-products
containers:
- name: worker
image: workolik360/nats-worker:v1.1.0
imagePullPolicy: IfNotPresent
command: ["python3", "-u", "/scripts/worker.py"]
volumeMounts:
- name: worker-script-vol
mountPath: /scripts
envFrom:
- configMapRef:
name: core-config
env:
- name: NATS_STREAM
value: "PRODUCTS"
- name: NATS_CONSUMER
value: "products-worker"
- name: FILTER_SUBJECT
value: "api.v1.web.products.create"
- name: WORKER_CONCURRENCY
value: "5"
- name: NATS_USER
valueFrom:
secretKeyRef:
name: nats-credentials
key: username
- name: NATS_PASSWORD
valueFrom:
secretKeyRef:
name: nats-credentials
key: password
- name: EXTERNAL_ENDPOINT_API_KEY
valueFrom:
secretKeyRef:
name: external-endpoint-secrets
key: api_key
optional: true
- name: EXTERNAL_BASE_URL
value: "http://10.43.229.168"
resources:
requests:
memory: "128Mi"
cpu: "40m"
limits:
memory: "256Mi"
cpu: "200m"
ports:
- containerPort: 9090
name: metrics
volumes:
- name: worker-script-vol
configMap:
name: worker-script