Buffering & Flushing

Smart strategies for buffering and flushing logs in Triton for optimal performance and reliability across Apex and LWC.

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

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

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

Smart Buffering with Limits

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.

Last updated