🔄 Transactions¶
Was ist eine Transaction?¶
Jede Operation in Polycrate wird als Transaction ausgeführt. Eine Transaction ist eine eindeutig identifizierte Ausführung einer Action mit vollständigem Logging, Event-Generation und Audit-Trail.
Jede Transaction erhält eine eindeutige UUID.
Transaction-Logging ist standardmäßig deaktiviert
Das Logging von Workspace Transactions ist standardmäßig deaktiviert. Das .logs/ Verzeichnis wird primär von Event-Handlers verwendet.
Um Transaction-Logging zu aktivieren, konfigurieren Sie dies in Ihrer workspace.poly:
Alle folgenden Beispiele setzen voraus, dass Transaction-Logging aktiviert ist.
Wenn Transaction-Logging aktiviert ist, werden Transactions vollständig geloggt in:
Transaction-Lifecycle¶
sequenceDiagram
participant User
participant CLI
participant Container
participant Action
participant Event
participant Log
User->>CLI: polycrate run myblock install
CLI->>CLI: Generiere TX-ID (UUID)
CLI->>CLI: Lade Workspace
CLI->>CLI: Erstelle Snapshot
CLI->>Container: Starte Container mit TX-ID
Container->>Action: FĂĽhre Action aus
alt Action erfolgreich
Action-->>Container: Exit 0
Container-->>CLI: Success
CLI->>Event: Generiere Success-Event
CLI->>Log: Schreibe TX-Log
Event->>Webhook: POST Event (optional)
else Action fehlgeschlagen
Action-->>Container: Exit 1
Container-->>CLI: Failure
CLI->>Event: Generiere Failure-Event
CLI->>Log: Schreibe TX-Log mit Error
Event->>Webhook: POST Event (optional)
end
CLI->>CLI: Cleanup Container
CLI-->>User: Ausgabe
style CLI fill:#e1f5ff
style Log fill:#ffe1e1
style Event fill:#fff4e1 Transaction-ID¶
Jede Transaction erhält eine eindeutige UUID im Format:
Diese ID wird verwendet fĂĽr: - Log-Dateinamen: .logs/2025-01-30/<uuid>.yml - Container-Namen: polycrate-<uuid> - Event-Tracking: Transaction-ID in Events - Git-Commits: Transaction-ID in Commit-Messages (optional) - Debugging: Eindeutige Identifikation einer AusfĂĽhrung
Transaction-Logs¶
Jede Transaction wird vollständig geloggt. Der Log enthält:
Log-Struktur¶
# .logs/2025-01-30/550e8400-e29b-41d4-a716-446655440000.yml
transaction:
id: 550e8400-e29b-41d4-a716-446655440000
start_time: "2025-01-30T10:30:00Z"
end_time: "2025-01-30T10:32:15Z"
duration: 135000 # Millisekunden
command: "polycrate run my-postgres install"
exit_code: 0
status: success # success oder failure
user:
name: John Doe
email: john@example.com
hostname: workstation.local
workspace:
name: my-workspace
path: /home/user/workspaces/my-workspace
git:
commit_sha: abc123def456
branch: main
dirty: false
block:
name: my-postgres
kind: k8sapp
version: 1.0.0
from: postgres-base
action:
name: install
description: Install PostgreSQL
playbook: playbooks/install.yml
snapshot:
# Vollständiger Workspace-Snapshot (siehe snapshot.md)
workspace: { ... }
block: { ... }
inventory: { ... }
kubeconfig: { ... }
output:
stdout: |
Installing PostgreSQL...
TASK [Install Helm Chart] ******************
ok: [localhost]
PLAY RECAP *********************************
localhost: ok=5 changed=2 failed=0
stderr: |
# Fehler-Ausgabe (falls vorhanden)
events:
- type: transaction_started
timestamp: "2025-01-30T10:30:00Z"
sent: true
- type: transaction_completed
timestamp: "2025-01-30T10:32:15Z"
sent: true
webhook_url: https://hooks.example.com/polycrate
webhook_status: 200
Log-Speicherort¶
Logs werden nach Datum organisiert:
.logs/
├── 2025-01-28/
│ ├── 123e4567-e89b-12d3-a456-426614174000.yml
│ ├── 234e5678-e89b-12d3-a456-426614174001.yml
│ └── 345e6789-e89b-12d3-a456-426614174002.yml
├── 2025-01-29/
│ ├── 456e7890-e89b-12d3-a456-426614174003.yml
│ └── 567e8901-e89b-12d3-a456-426614174004.yml
└── 2025-01-30/
└── 550e8400-e29b-41d4-a716-446655440000.yml
Transaction-Logs anzeigen¶
Letzte Logs anzeigen¶
# Alle Logs vom heutigen Tag
ls -lah .logs/$(date +%Y-%m-%d)/
# Letzten Log anzeigen
ls -t .logs/*/*.yml | head -1 | xargs cat
# Letzten Log mit yq formatieren
ls -t .logs/*/*.yml | head -1 | xargs yq
Logs einer bestimmten Transaction¶
# Transaction-ID aus Ausgabe kopieren:
# "Transaction ID: 550e8400-e29b-41d4-a716-446655440000"
cat .logs/2025-01-30/550e8400-e29b-41d4-a716-446655440000.yml
Logs nach Exit-Code filtern¶
# Alle fehlgeschlagenen Transactions
grep -r "exit_code: [^0]" .logs/
# Alle erfolgreichen Transactions
grep -r "exit_code: 0" .logs/
# Fehlerhafte Transactions mit Details
find .logs/ -name "*.yml" -exec sh -c '
if grep -q "exit_code: [^0]" "$1"; then
echo "=== Failed Transaction: $1 ==="
yq ".transaction.id, .action.name, .output.stderr" "$1"
fi
' _ {} \;
Logs nach Block filtern¶
# Alle Transactions fĂĽr einen Block
find .logs/ -name "*.yml" -exec grep -l "block.name: my-postgres" {} \;
# Transactions fĂĽr einen Block mit Datum
find .logs/ -name "*.yml" -exec sh -c '
if grep -q "name: my-postgres" "$1"; then
echo "$1: $(yq ".transaction.start_time" "$1")"
fi
' _ {} \;
Events¶
Jede Transaction kann optional Events generieren, die an Webhooks gesendet werden.
Event-Konfiguration¶
In workspace.poly:
name: my-workspace
events:
handler: webhook # oder monk
endpoint: https://hooks.example.com/polycrate
commit: true # Git-Commit nach Transaction
Event-Struktur¶
Events enthalten den vollständigen Transaction-Kontext:
{
"transaction": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-01-30T10:32:15Z",
"exit_code": 0,
"duration": 135000
},
"workspace": "my-workspace",
"block": "my-postgres",
"action": "install",
"command": "polycrate run my-postgres install",
"user": {
"name": "John Doe",
"email": "john@example.com"
},
"snapshot": { ... },
"output": "Installing PostgreSQL...\nok: [localhost]",
"message": "Transaction completed successfully"
}
Git-Integration¶
Polycrate kann automatisch Git-Commits mit Transaction-IDs erstellen:
Auto-Commit aktivieren¶
# workspace.poly
name: my-workspace
events:
commit: true # Git-Commit nach erfolgreicher Transaction
sync_options:
enabled: true
auto: true # Automatischer Push nach Commit
remote:
name: origin
url: git@github.com:user/workspace.git
branch:
name: main
Commit-Message-Format¶
Action: install block my-postgres
Transaction: 550e8400-e29b-41d4-a716-446655440000
Exit Code: 0
Duration: 2m 15s
Changes:
- Updated artifacts/blocks/my-postgres/
- Updated .logs/2025-01-30/
🤖 Generated with Polycrate
Co-Authored-By: Polycrate <noreply@polycrate.io>
Transaction-Context in Actions¶
Die Transaction-ID ist in Actions verfĂĽgbar:
Als Environment-Variable¶
echo "Transaction ID: $POLYCRATE_TRANSACTION_ID"
echo "Transaction Start: $POLYCRATE_TRANSACTION_START_TIME"
In Ansible-Playbooks¶
---
- name: Deploy Application
hosts: localhost
connection: local
tasks:
- name: Debug Transaction-Info
debug:
msg: |
Transaction ID: {{ transaction.id }}
Started at: {{ transaction.timestamp }}
User: {{ user.name }} <{{ user.email }}>
In Bash-Scripts (Template-Syntax)¶
actions:
- name: deploy
script:
- |
echo "=== Deployment via Transaction {{ .transaction.id }} ==="
echo "User: {{ .user.name }}"
echo "Timestamp: {{ .transaction.timestamp }}"
# ... deployment logic ...
echo "Transaction completed"
Monitoring mit Transactions¶
Transaction-Metriken¶
Transactions können für Monitoring und Metriken genutzt werden:
#!/bin/bash
# transaction-stats.sh
LOGS_DIR=".logs"
echo "=== Transaction Statistics ==="
# Gesamt-Anzahl
TOTAL=$(find $LOGS_DIR -name "*.yml" | wc -l)
echo "Total Transactions: $TOTAL"
# Erfolgreiche vs. Fehlgeschlagene
SUCCESS=$(grep -r "exit_code: 0" $LOGS_DIR | wc -l)
FAILED=$(grep -r "exit_code: [^0]" $LOGS_DIR | wc -l)
echo "Successful: $SUCCESS"
echo "Failed: $FAILED"
# Durchschnittliche Dauer
AVG_DURATION=$(find $LOGS_DIR -name "*.yml" -exec yq ".transaction.duration" {} \; | \
awk '{sum+=$1; count++} END {if(count>0) print sum/count/1000 "s"}')
echo "Average Duration: $AVG_DURATION"
# Top 5 längste Transactions
echo -e "\n=== Longest Transactions ==="
find $LOGS_DIR -name "*.yml" -exec sh -c '
duration=$(yq ".transaction.duration" "$1")
action=$(yq ".action.name" "$1")
block=$(yq ".block.name" "$1")
echo "$duration $block/$action $1"
' _ {} \; | sort -rn | head -5 | \
awk '{printf "%d seconds - %s - %s\n", $1/1000, $2, $3}'
Prometheus-Metriken (Optional)¶
Exportieren Sie Transaction-Metriken fĂĽr Prometheus:
#!/usr/bin/env python3
# export-metrics.py
import yaml
import glob
from prometheus_client import CollectorRegistry, Gauge, write_to_textfile
registry = CollectorRegistry()
transactions_total = Gauge('polycrate_transactions_total',
'Total number of transactions', registry=registry)
transactions_failed = Gauge('polycrate_transactions_failed_total',
'Number of failed transactions', registry=registry)
transaction_duration = Gauge('polycrate_transaction_duration_seconds',
'Last transaction duration', ['block', 'action'], registry=registry)
# Parse transaction logs
for log_file in glob.glob('.logs/*/*.yml'):
with open(log_file, 'r') as f:
data = yaml.safe_load(f)
transactions_total.inc()
if data['transaction']['exit_code'] != 0:
transactions_failed.inc()
duration_sec = data['transaction']['duration'] / 1000
transaction_duration.labels(
block=data['block']['name'],
action=data['action']['name']
).set(duration_sec)
write_to_textfile('polycrate_metrics.prom', registry)
Best Practices¶
1. Regelmäßige Log-Rotation¶
Logs können sich ansammeln. Implementieren Sie Log-Rotation:
# cleanup-old-logs.sh
#!/bin/bash
LOGS_DIR=".logs"
RETENTION_DAYS=90
echo "Cleaning up logs older than $RETENTION_DAYS days..."
find $LOGS_DIR -name "*.yml" -mtime +$RETENTION_DAYS -delete
# Leere Verzeichnisse löschen
find $LOGS_DIR -type d -empty -delete
echo "Cleanup completed"
Als Cron-Job:
2. Logs fĂĽr Compliance¶
Transaction-Logs sind perfekt fĂĽr Compliance und Auditing:
# compliance-report.sh
#!/bin/bash
START_DATE="2025-01-01"
END_DATE="2025-01-31"
echo "=== Compliance Report: $START_DATE to $END_DATE ==="
find .logs/ -name "*.yml" -newermt "$START_DATE" ! -newermt "$END_DATE" | \
while read log; do
echo "---"
yq '{
"timestamp": .transaction.start_time,
"user": .user.email,
"action": (.block.name + "/" + .action.name),
"status": .transaction.status,
"changes": .workspace.git.commit_sha
}' "$log"
done
3. Transaction-IDs in Alerts¶
Nutzen Sie Transaction-IDs in Alerting-Systemen:
# Webhook-Handler fĂĽr Slack/Mattermost
actions:
- name: notify-on-failure
script:
- |
if [ $? -ne 0 ]; then
curl -X POST https://hooks.slack.com/services/XXX \
-H 'Content-Type: application/json' \
-d "{
\"text\": \"❌ Deployment Failed\",
\"blocks\": [{
\"type\": \"section\",
\"text\": {
\"type\": \"mrkdwn\",
\"text\": \"*Transaction:* \`{{ .transaction.id }}\`\n*Block:* {{ .block.name }}\n*Action:* {{ .action.name }}\n*User:* {{ .user.name }}\"
}
}]
}"
fi
4. Transaction-Replay¶
Reproduzieren Sie eine Transaction mit dem gespeicherten Snapshot:
# replay-transaction.sh
#!/bin/bash
TX_ID="$1"
LOG_FILE=$(find .logs/ -name "${TX_ID}.yml")
if [ -z "$LOG_FILE" ]; then
echo "Transaction $TX_ID not found"
exit 1
fi
# Extrahiere Befehl
COMMAND=$(yq ".transaction.command" "$LOG_FILE")
echo "Replaying transaction $TX_ID"
echo "Original command: $COMMAND"
echo ""
# FĂĽhre aus (mit Warnung)
read -p "Execute? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
eval "$COMMAND"
fi
Troubleshooting¶
Transaction-Logs sind leer¶
PrĂĽfen Sie Berechtigungen:
Container wurde nicht aufgeräumt¶
# Hängende Container finden
docker ps -a | grep polycrate
# Aufräumen
docker ps -a | grep polycrate | awk '{print $1}' | xargs docker rm -f
Zu viele Logs¶
Implementieren Sie Log-Rotation (siehe Best Practices oben).
Zusammenhang mit anderen Konzepten¶
- Snapshot: Jede Transaction erstellt einen Snapshot
- Events: Transactions generieren Events
- Artefakte: Änderungen an Artifacts werden in Transaction-Logs dokumentiert
- Container: Container wird mit Transaction-ID benannt
- Workflows: Jeder Workflow-Step ist eine eigene Transaction
Transaction-basiertes Debugging
Bei Problemen: Finden Sie die Transaction-ID in der Ausgabe und öffnen Sie den Log. Er enthält ALLES: Snapshot, Ausgabe, Fehler, Umgebung.