# Error Handling Documentation

## Overview

The cronjob system implements a comprehensive error handling mechanism that tracks errors at multiple levels and provides detailed logging for debugging and monitoring.

## Error Code System

### Hierarchical Error Codes

Error codes follow a three-level hierarchy:

```
{class_code}{method_code}{error_code}
```

**Example**: `0801A111001`
- `0801`: Class code (Cron class)
- `A111`: Method code (send_brith_noti)
- `001`: Specific error code

### Error Code Components

#### Class Code
- Defined in `$_class_code` static property
- For `Cron` class: `'0801'`
- Identifies which class generated the error

#### Method Code
- Defined per method in `$method_code` variable
- Examples:
  - `A111`: send_brith_noti
  - `A002`: prepare_rebate_session
  - `A201`: update_user_deposit_trunover
- Identifies which method generated the error

#### Error Code
- Specific error identifier within a method
- Common patterns:
  - `001`: General execution error
  - `002`: Validation error
  - `003`: Database error
- Defined when setting errors

### Setting Error Codes

```php
// In CronBase
static protected function _set_error_code($code) {
    static::$err_code = static::$_class_code . $code;
    static::$err_codes[] = static::$err_code;
}
```

**Usage**:
```php
static::_set_error_code($method_code . '001');  // Results in '0801A111001'
```

## Error Types

### 1. Validation Errors

**When**: Input validation fails

**Example**: Invalid date format
```php
static::validate_cron_date($date);
// Throws Xception with code '0801A410001'
```

**Error Code**: `A410001` (validation method)

**Handling**:
- Exception thrown immediately
- Execution stops
- No database record created

### 2. Database Record Errors

**When**: Failed to create/update cron record

**Example**: Database connection failure
```php
try {
    $cron_id = static::_record_cron($cron_code, $date);
} catch (exception $e) {
    $log = "Error recording cron in " . __METHOD__ . ".\n\n" . $e->getMessage();
    Log::logCriticalErrors($actionCode, $transCode, $log);
    $error = true;
}
```

**Error Code**: `{method_code}001` (e.g., `08010009001` for _record_cron)

**Handling**:
- Logged as critical error
- Execution stops (business logic not executed)
- No database record created

### 3. Business Logic Errors

**When**: Exception during business logic execution

**Example**: Model method throws exception
```php
try {
    $user = new User();
    $result = $user->insert_today_birth($date);
} catch (exception $e) {
    static::_set_error_code($method_code . '001');
    $log = $e->getCode() . ': ' . $e->getMessage() . "\n" . Util::format_trace($e->getTrace());
    static::_set_log($log);
    $exec_error = true;
}
```

**Error Code**: `{method_code}001` (e.g., `0801A111001`)

**Handling**:
- Error code set
- Error logged to `$logs`
- `$exec_error` flag set
- Execution continues to update step
- Cron marked as failed

### 4. Update Record Errors

**When**: Failed to update completion status

**Example**: Database update failure
```php
try {
    static::_update_complete_cron($cron_id, $success, $message);
} catch (exception $e) {
    $log = "Error update complete cron in " . __METHOD__ . ".\n\n" . $e->getMessage();
    Log::logCriticalErrors($actionCode, $transCode, $log);
}
```

**Error Code**: `{method_code}001` (e.g., `08010010001` for _update_complete_cron)

**Handling**:
- Logged as critical error
- Record may remain in "running" state
- Requires manual intervention

### 5. Business Logic Result Errors

**When**: Business logic returns error (not exception)

**Example**: Model method returns error array
```php
if ($result['error']) {
    $message = Util::format_array_to_text($result);
    $success = false;
}
```

**Handling**:
- No exception thrown
- Error message extracted from result
- `$success` set to false
- Cron marked as failed

## Error Logging

### Log Levels

#### 1. Critical Errors
**When**: Database operations fail

**Method**: `Log::logCriticalErrors($actionCode, $transCode, $log)`

**Parameters**:
- `$actionCode`: Combined class + method code (e.g., `0801A111`)
- `$transCode`: Transaction code (e.g., `cron-send-brith-noti`)
- `$log`: Error message

**Example**:
```php
Log::logCriticalErrors('0801A111', 'cron-send-brith-noti', 
    "Error recording cron in Cron::send_brith_noti.\n\nDatabase connection failed");
```

#### 2. Execution Errors
**When**: Business logic exceptions

**Storage**: Stored in `static::$logs` and saved to database `message` field

**Format**:
```
{exception_code}: {exception_message}
{stack_trace}
```

**Example**:
```
500: Database query failed
#0 /path/to/User.php(123): User->insert_today_birth()
#1 /path/to/Cron.php(59): Cron->send_brith_noti()
```

### Error Message Storage

Errors are stored in multiple places:

1. **Database `message` field**: Human-readable error message
2. **Database `err_code` field**: Machine-readable error code
3. **System logs**: Critical errors via `Log::logCriticalErrors()`
4. **Static `$logs` property**: Accumulated during execution

## Error Flow Diagram

```
┌─────────────────────┐
│  Validation Error   │
└──────────┬──────────┘
           │
           ▼
    ┌──────────────┐
    │ Throw        │
    │ Exception    │
    └──────────────┘
           │
           ▼
    [Execution Stops]

┌─────────────────────┐
│  Record Error       │
└──────────┬──────────┘
           │
           ▼
    ┌──────────────┐
    │ Log Critical │
    │ Set $error   │
    └──────┬───────┘
           │
           ▼
    [Skip Business Logic]

┌─────────────────────┐
│  Business Logic     │
│  Exception          │
└──────────┬──────────┘
           │
           ▼
    ┌──────────────┐
    │ Set Error    │
    │ Code         │
    │ Log Details  │
    │ Set Flag     │
    └──────┬───────┘
           │
           ▼
    [Continue to Update]

┌─────────────────────┐
│  Update Error       │
└──────────┬──────────┘
           │
           ▼
    ┌──────────────┐
    │ Log Critical │
    │ (Record may  │
    │  be stuck)   │
    └──────────────┘
```

## Error Recovery

### Automatic Recovery

Some methods support automatic retry:

**Pattern**: Rerun on Failure
```php
if (!static::is_cron_ran_success($cron_code, $date)) {
    // Execute even if previous attempt failed
}
```

**Methods Using This**:
- `login_user_update_game_wallet()`
- `distribute_comm()` (with `$rerun` parameter)

### Manual Recovery

**Stuck Cronjobs**:
- Query for `completed = 'n'` and old `started` timestamp
- Investigate cause
- Manually update or rerun

**Failed Cronjobs**:
- Review `message` and `err_code` fields
- Fix underlying issue
- Use `$rerun` parameter (if available) or manually trigger

## Error Code Reference

### CronBase Error Codes

| Code      | Method              | Description                    |
|-----------|---------------------|--------------------------------|
| 0002001   | _set_error_code     | Error setting error code       |
| 0003001   | _set_log            | Error setting log              |
| 0009001   | _record_cron        | Error recording cron           |
| 0010001   | _update_complete_cron| Error updating cron           |
| 0011001   | _record_rapid_cron  | Error recording rapid cron     |
| 0012001   | _update_complete_rapid_cron| Error updating rapid cron |
| 0400001   | is_cron_ran         | Error querying cron status     |
| 0401001   | is_cron_ran_success | Error querying success status  |

### Cron Error Codes

| Code      | Method                      | Description                    |
|-----------|-----------------------------|--------------------------------|
| A111001   | send_brith_noti             | Execution error                |
| A002001   | prepare_rebate_session      | Execution error                |
| A003001   | insert_bet_details          | Execution error                |
| A004001   | update_4d_win_number        | Execution error                |
| A005001   | get_4d_bet_details          | Execution error                |
| A006001   | login_user_update_game_wallet| Execution error               |
| A007001   | cancel_expired_speedpay_payment| Execution error            |
| A008001   | update_game_status          | Execution error                |
| A201001   | update_user_deposit_trunover| Execution error                |
| A202001   | calculate_user_rank         | Execution error                |
| A203001   | expired_feed_the_frog_chance| Execution error                |
| A204001   | expired_shuffle             | Execution error                |
| A205001   | get_game_bet_details        | Execution error                |
| A206001   | agent_turnover_comm         | Execution error                |
| A207001   | user_turnover_comm          | Execution error                |
| A208001   | distribute_comm             | Execution error                |
| A209001   | check_wepay_withdrawal_status| Execution error               |
| A410001   | validate_cron_date          | Invalid date format            |

## Best Practices

1. **Always set error codes** when catching exceptions
2. **Log detailed information** including stack traces
3. **Use transaction codes** for log correlation
4. **Store error messages** in database for audit trail
5. **Handle database errors separately** from business logic errors
6. **Provide actionable error messages** for operators
7. **Consider retry mechanisms** for transient failures
8. **Monitor error rates** and patterns

## Monitoring Errors

### Key Metrics

1. **Error Rate**: Percentage of failed executions
2. **Error Types**: Distribution of error codes
3. **Stuck Cronjobs**: Count of incomplete executions
4. **Recovery Time**: Time to resolve errors

### Queries

```sql
-- Error rate by cron type
SELECT code, 
       COUNT(*) as total,
       SUM(CASE WHEN success = 'n' THEN 1 ELSE 0 END) as failures,
       ROUND(100.0 * SUM(CASE WHEN success = 'n' THEN 1 ELSE 0 END) / COUNT(*), 2) as error_rate
FROM cron
WHERE odate >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY code;

-- Most common error codes
SELECT err_code, COUNT(*) as count
FROM cron
WHERE err_code IS NOT NULL
  AND odate >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY err_code
ORDER BY count DESC;
```
