Skip to content

Conversation

@perigrin
Copy link
Member

Summary

This PR fixes the production deployment failures and adds synchronous wrapper methods for the Stripe service.

Critical Production Fix

Database Configuration Update

The free-tier registry-postgres database expired on October 11, 2025, causing all Render deployments to fail since October 13 with crashloop errors:

could not translate host name "dpg-d311beodl3ps73dv37kg-a" to address: Name or service not known

Changes:

  • Updated render.yaml to reference registry-db (standard plan) instead of the expired free database
  • Updated all service environment variables (DB_URL, SQITCH_TARGET) to pull from registry-db

Action Required:
Resume the registry-db PostgreSQL instance from the Render dashboard before merging. Services will auto-deploy once the database is available.

Stripe Service Improvements

Synchronous Wrapper Methods

Added synchronous wrapper methods to Registry::Service::Stripe for backward compatibility with existing code that expects blocking behavior:

  • Payment Intents: create_payment_intent, retrieve_payment_intent, confirm_payment_intent, cancel_payment_intent
  • Customers: create_customer, retrieve_customer, update_customer, delete_customer
  • Payment Methods: create_payment_method, retrieve_payment_method, attach_payment_method, detach_payment_method, list_customer_payment_methods
  • Subscriptions: create_subscription, retrieve_subscription, update_subscription, cancel_subscription
  • Invoices: list_invoices, retrieve_invoice
  • Refunds: create_refund, retrieve_refund
  • Prices: create_price, retrieve_price, list_prices
  • Products: create_product, retrieve_product
  • Setup Intents: create_setup_intent

All wrappers use the ->wait pattern on the async versions for clean implementation.

Documentation Improvements

Enhanced CLAUDE.md with:

  • Test command conventions (always use -lr flags)
  • Common test failure solutions
  • Workflow development gotchas (workflow import requirement)
  • Database migration workflow with Sqitch steps

Test Results

All 112 test files pass (1,167 tests total):

  • ✅ 100% pass rate
  • ⚠️ 3 non-blocking Stripe promise warnings (tests using mock keys)

Deployment Impact

Before this PR:

  • All Render services suspended due to database connection failures
  • Services crashlooping every 5 minutes

After this PR (once registry-db is resumed):

  • Services will successfully deploy
  • Database connections will work
  • Stripe integration ready with both async and sync APIs

- Add synchronous wrapper methods to Registry::Service::Stripe for backward compatibility
- Document test command conventions and common test failures in CLAUDE.md
- Document workflow development gotchas and database migration workflow
- Add guidance on workflow import requirements and Sqitch migration steps

These changes support the fix-stripe-sync-wrappers branch work and improve
developer experience by documenting common pitfalls and solutions.
…es to registry-db

The free-tier registry-postgres database expired on Oct 11, causing all
deployments to fail with "could not translate host name" errors. Services
were stuck in crashloop trying to connect to the non-existent database.

Updated render.yaml to reference the existing registry-db (standard plan)
instance instead. This requires registry-db to be resumed from the Render
dashboard before services will successfully deploy.

Fixes deployment failures since Oct 13, 2025.
perigrin pushed a commit that referenced this pull request Nov 6, 2025
Refactored the entire workflow processing system to use asynchronous
operations with Mojo::Promise, eliminating event loop blocking during
I/O operations like Stripe API calls.

**Architecture Changes:**

1. **WorkflowStep Base Class** (`lib/Registry/DAO/WorkflowStep.pm`):
   - Added `process_async($db, $data)` method returning Mojo::Promise
   - Default implementation wraps sync `process()` for backwards compatibility
   - Subclasses can override for true async behavior

2. **WorkflowRun** (`lib/Registry/DAO/WorkflowRun.pm`):
   - Added `process_async($db, $step, $data)` returning Mojo::Promise
   - Chains step processing with database updates asynchronously
   - Maintains sync `process()` method for backwards compatibility

3. **Payment Workflow Step** (`lib/Registry/DAO/WorkflowSteps/Payment.pm`):
   - Implemented true async processing with `process_async()`
   - Added `create_payment_async()` for non-blocking Stripe API calls
   - Added `handle_payment_callback_async()` for async payment verification
   - Returns immediately resolved promises for non-async paths

4. **Payment DAO** (`lib/Registry/DAO/Payment.pm`):
   - Refactored sync methods to call async variants with `->wait`
   - `create_payment_intent()` now wraps `create_payment_intent_async()->wait`
   - `process_payment()` now wraps `process_payment_async()->wait`
   - `refund()` now wraps `refund_async()->wait`
   - Maintains backwards compatibility while using async infrastructure

5. **Workflows Controller** (`lib/Registry/Controller/Workflows.pm`):
   - Updated `process_workflow_run_step()` to return promises
   - Mojolicious automatically handles promise resolution
   - Added comprehensive error handling with `->catch()`
   - Event loop stays free during Stripe API calls

**Benefits:**

- **Non-blocking**: Event loop remains responsive during external API calls
- **Scalable**: Can handle many concurrent workflows without blocking
- **Modern**: Follows Mojolicious async/promise best practices
- **Backwards Compatible**: Sync methods still work for testing/CLI
- **Composable**: Easy to chain multiple async operations

**Documentation:**

Added comprehensive "Async Workflow Architecture" section to CLAUDE.md
covering:
- When to use async vs sync methods
- How to create async workflow steps
- Controller patterns for promise handling
- Complete Payment step example
- Migration path for existing code
- Benefits and testing approaches

**Testing:**

- Sync methods use `->wait` to block promises for simple test assertions
- Async methods can be tested by calling `->wait` on returned promises
- Base class ensures all steps have async support (wrapped or native)

**No Breaking Changes:**

- All existing sync code continues to work
- Base class provides automatic promise wrapping
- Gradual migration path for converting steps to async

This refactoring eliminates the need for synchronous Stripe API wrappers
that would block the event loop. The async architecture is the proper
solution for a Mojolicious application handling external API calls.

Fixes #86 review feedback - implements proper async instead of sync wrappers
@perigrin perigrin closed this Nov 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants