> For the complete documentation index, see [llms.txt](https://triton.pharos.ai/pharos-triton/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://triton.pharos.ai/pharos-triton/triton-best-practices/buffering-and-flushing.md).

# Buffering & Flushing

## Understanding Buffering vs Flushing

* **Apex:**
  * `addLog(builder)` buffers.
  * `log(builder)` **flushes immediately** (use at key boundaries or errors).
  * Triton sets stack trace & operation automatically when missing, and appends **governor limit** info via the builder.
* **LWC:**
  * `triton.log(builder)` buffers in memory.
  * `triton.logNow(builder)` flushes that one immediately.
  * Triton's LWC **TransactionManager** auto-flushes after idle periods; still **flush on navigation/unload** when practical.

## Real-World Example: Financial Transaction Processing

```apex
public class PaymentProcessor {
    public static void processPayment(Id accountId, Decimal amount) {
        Long startTime = System.now().getTime();
        
        // Set up template for all payment processing logs
        Triton.instance.setTemplate(
            Triton.makeBuilder()
                .category(TritonTypes.Category.Integration)
                .type(TritonTypes.Type.Backend)
                .area(TritonTypes.Area.PaymentProcessing)
                .relatedObject(accountId)
        );
        
        // Buffer routine operations using template
        Triton.instance.addLog(
            Triton.instance.fromTemplate()
                .level(TritonTypes.Level.DEBUG)
                .summary('Payment processing started')
                .details('accountId=' + accountId + ', amount=' + amount)
        );
        
        try {
            // First, make the callout to payment gateway
            HttpRequest req = new HttpRequest();
            req.setEndpoint('https://api.paymentgateway.com/process');
            req.setMethod('POST');
            req.setHeader('Content-Type', 'application/json');
            req.setBody(JSON.serialize(new Map<String, Object>{
                'accountId' => accountId,
                'amount' => amount,
                'currency' => 'USD'
            }));
            
            HttpResponse response = new Http().send(req);
            
            if (response.getStatusCode() == 200) {
                // Parse successful response
                Map<String, Object> responseData = (Map<String, Object>)JSON.deserializeUntyped(response.getBody());
                
                // Now perform DML after successful callout
                Payment__c payment = new Payment__c(
                    Account__c = accountId,
                    Amount__c = amount,
                    Status__c = 'Completed'
                );
                insert payment;
                
                // Buffer success milestone using template
                Triton.instance.addLog(
                    Triton.instance.fromTemplate()
                        .level(TritonTypes.Level.INFO)
                        .summary('Payment processed successfully')
                        .details('paymentId=' + payment.Id)
                        .relatedObject(payment.Id)
                        .integrationPayload(req, response)
                        .duration(System.now().getTime() - startTime)
                );
                
            } else {
                // Immediately flush critical error using template
                Triton.instance.log(
                    Triton.instance.fromTemplate()
                        .exception(new PaymentException('Gateway error: ' + response.getStatusCode()))
                        .summary('Payment gateway failed')
                        .integrationPayload(req, response)
                );
            }
            
        } catch (Exception e) {
            // Immediately flush critical errors using template
            Triton.instance.log(
                Triton.instance.fromTemplate()
                    .exception(e)
                    .summary('Payment processing failed')
            );
            throw e;
        } finally {
            // Flush all buffered logs at transaction boundary
            Triton.instance.flush();
        }
    }
}
```

## LWC Buffering Example

```js
// E-commerce checkout component with smart buffering
export default class CheckoutComponent extends LightningElement {
    triton;
    
    connectedCallback() {
        this.triton = new Triton().bindToComponent('c-checkout');
        
        // Set up template for all checkout operations
        this.triton.setTemplate(
            this.triton.makeBuilder()
                .type(TYPE.FRONTEND)
                .area(AREA.COMMUNITY)
        );
    }
    
    async handleCheckout() {
        // Buffer routine debug info
        this.triton.log(
            this.triton.fromTemplate()
                .level(LEVEL.DEBUG)
                .summary('Checkout initiated')
                .details(JSON.stringify({ 
                    cartItems: this.cartItems.length,
                    totalAmount: this.totalAmount 
                }))
        );
        
        try {
            // Process checkout steps
            await this.validateInventory();
            await this.processPayment();
            await this.createOrder();
            
            // Buffer success milestone
            this.triton.log(
                this.triton.fromTemplate()
                    .level(LEVEL.INFO)
                    .summary('Checkout completed successfully')
                    .details(JSON.stringify({ orderId: this.orderId }))
            );
            
        } catch (error) {
            // Immediately flush critical errors
            await this.triton.logNow(
                this.triton.fromTemplate()
                    .exception(error)
                    .summary('Checkout failed')
            );
            
            // Show user-friendly error
            this.showErrorMessage('Checkout failed. Please try again or contact support.');
        }
    }
    
    disconnectedCallback() {
        // Flush any remaining logs when component is destroyed
        this.triton.flush();
    }
}
```

## When to Buffer vs Flush

### Buffer When:

* **Routine operations**: Normal processing steps, debug information
* **High-volume scenarios**: Processing multiple records in loops
* **Performance-critical paths**: Where logging overhead must be minimized
* **Non-critical information**: Debug logs, informational milestones

### Flush Immediately When:

* **Critical errors**: Exceptions that might prevent further processing
* **Transaction boundaries**: End of methods, batch chunks, queueable completion
* **User-facing failures**: Errors that affect user experience
* **Integration failures**: Callout errors, external service issues
* **Component teardown**: LWC component destruction

## Performance Considerations

### Apex Performance

* **Buffering reduces DML**: Multiple logs are sent together, reducing platform event overhead
* **Flush strategically**: Use `flush()` at natural boundaries to avoid memory buildup
* **Error scenarios**: Always flush on errors to ensure critical information is captured
* **Governor limits**: Monitor platform event limits in high-volume scenarios

### LWC Performance

* **Memory management**: Buffered logs consume memory until flushed
* **Auto-flush**: Triton automatically flushes after idle periods
* **Navigation events**: Flush on page navigation or component destruction
* **Error handling**: Use `logNow()` for critical errors to ensure immediate capture

## Best Practices

### Buffer Management

1. **Set clear boundaries**: Define when to flush based on logical transaction boundaries
2. **Monitor memory usage**: Be aware of buffered log volume in long-running processes
3. **Error handling**: Always flush on exceptions to preserve critical context
4. **Performance testing**: Measure the impact of buffering vs immediate flushing

### Flush Strategies

1. **Method boundaries**: Flush at the end of public methods
2. **Batch operations**: Flush after each batch chunk
3. **Queueable completion**: Flush at the end of queueable execution
4. **Component lifecycle**: Flush in LWC `disconnectedCallback()`
5. **Error scenarios**: Immediate flush for all exceptions

### Monitoring and Debugging

1. **Log volume**: Monitor the number of buffered vs flushed logs
2. **Memory usage**: Track memory consumption in long-running processes
3. **Error correlation**: Ensure errors are properly flushed for debugging
4. **Performance impact**: Measure the overhead of different buffering strategies

## Advanced Patterns

### Conditional Flushing

```apex
public void processRecords(List<SObject> records) {
    for (SObject record : records) {
        // Buffer routine processing
        Triton.instance.addLog(
            Triton.instance.fromTemplate()
                .summary('Processing record')
                .relatedObject(record.Id)
        );
        
        try {
            processRecord(record);
        } catch (Exception e) {
            // Flush immediately on error
            Triton.instance.log(
                Triton.instance.fromTemplate()
                    .exception(e)
                    .summary('Record processing failed')
            );
            throw e;
        }
    }
    
    // Flush all buffered logs at the end
    Triton.instance.flush();
}
```

### Smart Buffering with Limits

```apex
public class SmartBuffer {
    private static final Integer MAX_BUFFER_SIZE = 50;
    private static Integer bufferCount = 0;
    
    public static void addLog(TritonBuilder builder) {
        Triton.instance.addLog(builder);
        bufferCount++;
        
        // Flush when buffer gets too large
        if (bufferCount >= MAX_BUFFER_SIZE) {
            Triton.instance.flush();
            bufferCount = 0;
        }
    }
    
    public static void forceFlush() {
        Triton.instance.flush();
        bufferCount = 0;
    }
}
```

By mastering buffering and flushing strategies, you'll optimize performance while ensuring critical logs are never lost and debugging information is always available when needed.
