PSA/docs/workflow/workflow-troubleshooting.md
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

433 lines
14 KiB
Markdown

# Workflow Troubleshooting Guide
This document provides solutions to common issues encountered when working with the workflow system.
## Table of Contents
1. [Action Not Found Errors](#action-not-found-errors)
2. [Workflow Deserialization Errors](#workflow-deserialization-errors)
3. [Database Update Issues](#database-update-issues)
4. [Test Environment Issues](#test-environment-issues)
## Action Not Found Errors
### Problem: `actions.resolve_email_provider_defaults is not a function`
**Symptoms:**
- Workflow fails with error: `actions.resolve_email_provider_defaults is not a function`
- Error occurs during email processing workflow execution
**Root Cause:**
The workflow code in the database still references an old action name that has been deprecated or renamed.
**Solution:**
1. **Update the workflow source code** to use the new action name
2. **Update the database** using the appropriate update script
3. **Verify the database contains the updated code**
**Example Fix:**
```javascript
// OLD (deprecated)
const ticketDefaults = await actions.resolve_email_provider_defaults({
providerId: providerId,
tenant: tenant
});
// NEW (correct)
const ticketDefaults = await actions.resolve_inbound_ticket_defaults({
tenant: tenant
});
```
**Verification Steps:**
```sql
-- Check what action names are in the database
SELECT
sv.version_id,
sv.is_current,
LENGTH(sv.code) as code_length,
CASE
WHEN sv.code LIKE '%resolve_email_provider_defaults%' THEN 'OLD_ACTION'
WHEN sv.code LIKE '%resolve_inbound_ticket_defaults%' THEN 'NEW_ACTION'
ELSE 'UNKNOWN'
END as action_status
FROM system_workflow_registration_versions sv
WHERE sv.registration_id = '550e8400-e29b-41d4-a716-446655440001'
ORDER BY sv.created_at DESC;
```
## Workflow Deserialization Errors
### Problem: `Unexpected token 'async'`
**Symptoms:**
- Error: `SyntaxError: Unexpected token 'async'`
- Occurs when workflow runtime tries to deserialize workflow function
- Error in `deserializeWorkflowFunction`
**Root Cause:**
The workflow function stored in the database contains incorrect syntax that conflicts with how the runtime wraps the function.
**Solution:**
The stored function should NOT have `async` in the wrapper as the runtime adds it automatically.
```javascript
// CORRECT - runtime adds async wrapper
const dbWorkflowCode = `function execute(context) {
// workflow body
}`;
```
### Problem: `Failed to extract function body from compiled code`
**Symptoms:**
- Error: `Failed to extract function body from compiled code`
- Occurs during workflow deserialization
- Error in `deserializeWorkflowFunction`
**Root Cause:**
The workflow runtime expects stored functions to match the pattern `async function <name>(context) { ... }` but the stored function doesn't match this pattern.
**Solution:**
Ensure the stored function matches the expected pattern:
```javascript
// CORRECT - matches runtime expectations
const dbWorkflowCode = `async function execute(context) {
${functionBody}
}`;
```
**Common Issues:**
1. **Missing async keyword**: Function stored as `function execute(context)` instead of `async function execute(context)`
2. **TypeScript imports**: Import statements in the workflow code
3. **Type annotations**: TypeScript type annotations like `context: WorkflowContext`
4. **Async function declarations within workflow**: Helper functions declared as `async function name() {}` inside the main workflow
### Problem: `Unexpected token 'async'` with helper functions
**Symptoms:**
- Error: `SyntaxError: Unexpected token 'async'`
- Occurs when workflow contains helper functions declared as `async function`
- Runtime fails to parse the wrapped function
**Root Cause:**
Helper functions declared as `async function name() {}` within the workflow cause parsing errors when the runtime wraps the extracted function body.
**Solution:**
Convert helper function declarations to function expressions:
```javascript
// WRONG - causes parsing error
async function checkEmailThreading(emailData, actions) {
// ...
}
// CORRECT - use function expressions
const checkEmailThreading = async (emailData, actions) => {
// ...
};
// Also correct - function expression syntax
const checkEmailThreading = async function(emailData, actions) {
// ...
};
```
**Why this happens:**
The runtime wraps the extracted function body like this:
```javascript
return (async function(context) {
// Your extracted function body goes here
async function helperFunction() {} // <-- This causes the error!
})(context);
```
Function declarations inside immediately invoked function expressions cause JavaScript parsing errors.
**Issue 2: Remove imports and TypeScript syntax**
```typescript
// WRONG - TypeScript syntax
import type { WorkflowContext } from '../core/types.js';
export async function systemEmailProcessingWorkflow(context: WorkflowContext): Promise<void> {
// workflow logic
}
// CORRECT - Plain JavaScript
export async function systemEmailProcessingWorkflow(context) {
// workflow logic
}
```
**Issue 3: Update tsconfig to exclude workflow files**
```json
{
"exclude": ["node_modules", "dist", "workflow/workflows/system-email-processing-workflow.ts"]
}
```
### Problem: Helper functions not accessible in workflow scope
**Symptoms:**
- Workflow deserialization succeeds initially
- Runtime errors when helper functions are called
- Functions appear undefined during execution
- Error: `checkEmailThreading is not defined` or similar
**Root Cause:**
The workflow runtime extracts only the function body and wraps it in a new execution context. Helper functions defined outside the main workflow function are not included in the extracted body, making them inaccessible during execution.
**Solution:**
**All helper functions must be defined inside the main workflow function** using function expressions:
```javascript
export async function systemEmailProcessingWorkflow(context) {
const { actions, data, logger, setState, events } = context;
// CORRECT - Helper functions defined inside main function as const expressions
const checkEmailThreading = async (emailData, actions) => {
// helper function logic
};
const handleEmailReply = async (emailData, existingTicket, actions) => {
// helper function logic
};
const findExactEmailMatch = async (emailAddress, actions) => {
// helper function logic
};
// Main workflow logic starts here
setState('PROCESSING_INBOUND_EMAIL');
// ... rest of workflow
}
// WRONG - Helper functions outside main function won't be included
async function checkEmailThreading(emailData, actions) {
// This function won't be available during execution!
}
export async function systemEmailProcessingWorkflow(context) {
// Main workflow logic - but helper functions are missing!
}
```
**Why this happens:**
1. The runtime extracts only the content between the first `{` and last `}` of the main function
2. Functions defined outside the main function are not included in the extraction
3. The extracted body is wrapped in a new execution context where external functions don't exist
**Key Requirements:**
- Use `const functionName = async () => {}` syntax inside the main function
- Never use `async function functionName() {}` declarations inside the main function (causes parsing errors)
- Never define helper functions outside the main workflow function
### Problem: Function body extraction issues
**Symptoms:**
- Error: `Could not find systemEmailProcessingWorkflow function in source file`
- Seed fails during workflow loading
**Root Cause:**
The regex or string parsing logic in the seed file doesn't match the actual function signature.
**Solution:**
Use simple string indexing instead of complex regex:
```javascript
// Find the function declaration and extract everything after the opening brace
const functionStart = workflowContent.indexOf('export async function systemEmailProcessingWorkflow(context) {');
if (functionStart === -1) {
throw new Error('Could not find systemEmailProcessingWorkflow function in source file');
}
// Find the opening brace and extract everything after it, minus the final closing brace
const openBraceIndex = workflowContent.indexOf('{', functionStart);
const functionContent = workflowContent.substring(openBraceIndex + 1);
// Remove the final closing brace
const functionBody = functionContent.substring(0, functionContent.lastIndexOf('}')).trim();
```
## Database Update Issues
### Problem: Workflow updates not taking effect
**Symptoms:**
- Updated workflow code in source file
- Ran update script successfully
- But runtime still executes old workflow code
**Root Causes:**
1. **Multiple databases**: Update script connected to different database than runtime
2. **Test seeds overwriting**: Test environment seeds overwrite manual updates
3. **Caching issues**: Workflow runtime caching old definitions
**Solutions:**
**Issue 1: Verify correct database connection**
```bash
# Check which databases are running
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep postgres
# Use correct environment variables
DB_HOST=localhost DB_PORT=5433 DB_NAME_SERVER=server_test DB_USER_ADMIN=postgres DB_PASSWORD_ADMIN=postpass123 node scripts/update-workflow-in-db.cjs
```
**Issue 2: Update seed files to read from source**
Ensure seed files read from the actual TypeScript source instead of hardcoded workflow code:
```javascript
// WRONG - hardcoded workflow
const dbWorkflowCode = `async function execute(context) {
// hardcoded workflow logic here
}`;
// CORRECT - read from source file
function loadWorkflowCodeFromSource() {
const workflowPath = path.join(__dirname, '../../../shared/workflow/workflows/system-email-processing-workflow.ts');
const workflowContent = fs.readFileSync(workflowPath, 'utf8');
// extract and convert workflow code
}
```
**Issue 3: Check workflow version IDs**
Verify the update script is updating the correct version:
```sql
-- Check all workflow versions
SELECT
sv.version_id,
sv.is_current,
sv.created_at,
sv.updated_at,
LENGTH(sv.code) as code_length
FROM system_workflow_registration_versions sv
WHERE sv.registration_id = '550e8400-e29b-41d4-a716-446655440001'
ORDER BY sv.created_at DESC;
```
## Test Environment Issues
### Problem: Tests overwrite workflow updates
**Symptoms:**
- Manual workflow updates work
- Tests reset workflow to old version
- Tests fail with old action errors
**Root Cause:**
Test environment runs seeds that overwrite workflow definitions with outdated code.
**Solution:**
Update the seed file to load from the current source file instead of hardcoded workflow:
```javascript
// File: /server/seeds/dev/004_email_processing_workflow_from_source.cjs
function loadWorkflowCodeFromSource() {
const workflowPath = path.join(__dirname, '../../../shared/workflow/workflows/system-email-processing-workflow.ts');
if (!fs.existsSync(workflowPath)) {
throw new Error(`Workflow file not found: ${workflowPath}`);
}
console.log(`Reading workflow from source file: ${workflowPath}`);
const workflowContent = fs.readFileSync(workflowPath, 'utf8');
// Extract function body and create database-compatible version
// ... (extraction logic)
return dbWorkflowCode;
}
```
### Problem: Multiple workflow registrations
**Symptoms:**
- Multiple entries for the same workflow
- Unclear which version is being executed
**Diagnosis:**
```sql
-- Check all email-related workflows
SELECT
sr.registration_id,
sr.name,
sr.status,
sv.version_id,
sv.is_current,
LENGTH(sv.code) as code_length
FROM system_workflow_registrations sr
JOIN system_workflow_registration_versions sv ON sr.registration_id = sv.registration_id
WHERE sr.name LIKE '%email%' OR sv.code LIKE '%email%'
ORDER BY sr.name, sv.created_at DESC;
```
**Solution:**
Ensure only one registration exists with the correct static UUID and that only one version is marked as current.
## Debugging Tips
### 1. Check Workflow Runtime Logs
Look for these log patterns:
- `[TENANT-DEBUG] WorkflowWorker about to start workflow`
- `Error deserializing workflow function`
- `Failed to load system workflow definition`
### 2. Verify Database State
```sql
-- Check current workflow registration
SELECT * FROM system_workflow_registrations
WHERE registration_id = '550e8400-e29b-41d4-a716-446655440001';
-- Check current version
SELECT * FROM system_workflow_registration_versions
WHERE registration_id = '550e8400-e29b-41d4-a716-446655440001'
AND is_current = true;
```
### 3. Test Workflow Updates
Use the improved update script with detailed logging:
```bash
# The script provides comprehensive feedback
node scripts/update-workflow-in-db.cjs
```
### 4. Validate Workflow Syntax
Before updating the database, ensure the workflow function:
- Has no TypeScript imports
- Uses plain JavaScript syntax
- Function signature matches: `export async function systemEmailProcessingWorkflow(context)`
- Contains expected action calls
## Prevention Best Practices
1. **Keep workflows simple**: Avoid TypeScript syntax in workflow files
2. **Use seed files that read from source**: Don't hardcode workflow logic in seeds
3. **Exclude workflow files from TypeScript compilation**: Add to tsconfig exclude
4. **Test workflow updates**: Verify database state after updates
5. **Use consistent database connections**: Ensure update scripts target the correct database
6. **Version control workflow changes**: Track both source and database updates
## Quick Reference
### Common Commands
```bash
# Update workflow in database
DB_HOST=localhost DB_PORT=5433 DB_NAME_SERVER=server_test DB_USER_ADMIN=postgres DB_PASSWORD_ADMIN=postpass123 node scripts/update-workflow-in-db.cjs
# Check database workflows
docker exec sebastian_postgres_test psql -U postgres -d server_test -c "SELECT name, status FROM system_workflow_registrations;"
# Check running containers
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep postgres
```
### Workflow File Requirements
- Plain JavaScript syntax only
- No TypeScript imports
- No type annotations
- Function signature: `export async function systemEmailProcessingWorkflow(context)`
- Store as `function execute(context)` in database (no async keyword)