交付流程 · 產物閱讀
PYexamples/quality-workflow/demo_app/payment_service.py

payment_service.py

"""Small, real HTTP + SQLite teaching service. Never use for real payments."""

import argparse
import json
import sqlite3
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path


def serve(database, ready_file, fault):
    class Handler(BaseHTTPRequestHandler):
        def log_message(self, *args):
            pass

        def reply(self, status, body):
            encoded = json.dumps(body).encode("utf-8")
            self.send_response(status)
            self.send_header("Content-Type", "application/json")
            self.send_header("Content-Length", str(len(encoded)))
            self.end_headers()
            self.wfile.write(encoded)

        def do_POST(self):
            if self.path != "/payments":
                return self.reply(404, {"error": "NOT_FOUND"})
            try:
                length = int(self.headers.get("Content-Length", "0"))
                if not 0 < length <= 4096:
                    raise ValueError("invalid body length")
                payload = json.loads(self.rfile.read(length))
                order_id = payload.get("order_id") if isinstance(payload, dict) else None
                if not isinstance(order_id, str) or not order_id.strip():
                    raise ValueError("order_id is required")
            except (ValueError, UnicodeDecodeError):
                return self.reply(400, {"error": "INVALID_REQUEST"})

            connection = sqlite3.connect(database, timeout=5)
            try:
                # Acquire the write transaction before reading: concurrent requests
                # cannot both observe PENDING and both create a payment.
                connection.execute("BEGIN IMMEDIATE")
                row = connection.execute(
                    "SELECT status FROM orders WHERE id = ?", (order_id,)
                ).fetchone()
                if row is None:
                    connection.rollback()
                    return self.reply(404, {"error": "ORDER_NOT_FOUND"})
                if row[0] == "PAID":
                    if fault == "duplicate-write":
                        connection.execute(
                            "INSERT INTO payments(order_id) VALUES (?)", (order_id,)
                        )
                        connection.commit()
                    else:
                        connection.rollback()
                    error = "INVALID_STATE" if fault == "wrong-error" else "ORDER_ALREADY_PAID"
                    return self.reply(409, {"error": error})
                connection.execute("INSERT INTO payments(order_id) VALUES (?)", (order_id,))
                connection.execute("UPDATE orders SET status = 'PAID' WHERE id = ?", (order_id,))
                connection.commit()
                return self.reply(200, {"order_id": order_id, "status": "PAID"})
            finally:
                connection.close()

    server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
    Path(ready_file).write_text(json.dumps({
        "host": "127.0.0.1", "port": server.server_port,
        "implementation": "quality-workflow-payment-demo", "fault": fault,
    }), encoding="utf-8")
    server.serve_forever()


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--db", required=True)
    parser.add_argument("--ready-file", required=True)
    parser.add_argument("--fault", choices=["none", "duplicate-write", "wrong-error"], default="none")
    args = parser.parse_args()
    serve(args.db, args.ready_file, args.fault)

靜態唯讀副本 · 可直接開啟,不需伺服器;不改變核准或執行結果