Initial commit
This commit is contained in:
19
manifests/core/core-config.yaml
Normal file
19
manifests/core/core-config.yaml
Normal 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"
|
||||
6
manifests/core/core-namespace.yaml
Normal file
6
manifests/core/core-namespace.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: core
|
||||
labels:
|
||||
name: core
|
||||
25
manifests/core/core-secrets.yaml
Normal file
25
manifests/core/core-secrets.yaml
Normal 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
|
||||
76
manifests/core/ingress-unified.yaml
Normal file
76
manifests/core/ingress-unified.yaml
Normal 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
|
||||
12
manifests/core/kustomization.yaml
Normal file
12
manifests/core/kustomization.yaml
Normal 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
|
||||
41
manifests/core/traefik-middlewares.yaml
Normal file
41
manifests/core/traefik-middlewares.yaml
Normal 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
|
||||
13
manifests/core/worker-pdb.yaml
Normal file
13
manifests/core/worker-pdb.yaml
Normal 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
|
||||
261
manifests/core/worker-script.yaml
Normal file
261
manifests/core/worker-script.yaml
Normal 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())
|
||||
129
manifests/core/worker-statefulset.yaml
Normal file
129
manifests/core/worker-statefulset.yaml
Normal 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
542
manifests/core/workers.yaml
Normal 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
|
||||
Reference in New Issue
Block a user