Skip to Content
ResourcesBest PracticesPerformance Optimization

Performance Optimization

This document introduces performance optimization recommendations for merchants integrating SUNBAY API.

Use SDK

Recommended to Use Official SDK

The SDK provided by SUNBAY has built-in connection pools, retry mechanisms, timeout controls, and other optimizations. It is strongly recommended to use the SDK rather than calling the API directly.

SDK has already handled for you:

  • ✅ HTTP connection pool management
  • ✅ Connection reuse
  • ✅ Reasonable timeout settings
  • ✅ Automatic retry mechanism

See SDK Documentation for usage details.

Cache Query Results

For data that doesn’t change frequently, you can cache query results to reduce API calls.

Data Suitable for Caching

  • ✅ Merchant configuration information
  • ✅ Payment method list
  • ✅ Completed transaction details (status is final)

Data Not Suitable for Caching

  • ❌ Transaction status in processing (PROCESSING, INITIAL)
  • ❌ Real-time balance information

Caching Example

import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import java.util.concurrent.TimeUnit; public class TransactionCache { // Cache completed transactions (final states) private final Cache<String, TransactionDetail> cache = Caffeine.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .maximumSize(1000) .build(); /** * Get transaction details (with cache) */ public TransactionDetail getTransaction(String transactionId) { return cache.get(transactionId, id -> { // Cache miss, call API to query QueryResponse response = client.query( QueryRequest.builder() .transactionId(id) .build() ); TransactionDetail detail = response.getData(); // Only cache final state transactions if (isFinalStatus(detail.getTransactionStatus())) { return detail; } return null; // Don't cache non-final states }); } private boolean isFinalStatus(String status) { return "SUCCESS".equals(status) || "FAIL".equals(status) || "CLOSED".equals(status); } }

Asynchronous Webhook Processing

Webhook processing should return 200 response quickly to avoid timeouts.

SUNBAY’s Webhook request timeout is 10 seconds; if timeout occurs, it will trigger retry.

@RestController @RequestMapping("/webhook") public class WebhookController { private final ExecutorService executorService = Executors.newFixedThreadPool(10); @PostMapping("/payment") public ResponseEntity<String> handlePaymentWebhook( @RequestBody String payload, @RequestHeader("X-SUNBAY-Signature") String signature) { // 1. Quick signature verification if (!webhookValidator.verifySignature(payload, signature)) { return ResponseEntity.status(401).body("Invalid signature"); } // 2. Return 200 immediately executorService.submit(() -> { try { // 3. Process event asynchronously processWebhookEvent(payload); } catch (Exception e) { log.error("Failed to process webhook", e); } }); return ResponseEntity.ok("OK"); } }

Use Message Queue (Optional)

For high-concurrency scenarios, you can use message queues:

@PostMapping("/payment") public ResponseEntity<String> handlePaymentWebhook( @RequestBody String payload, @RequestHeader("X-SUNBAY-Signature") String signature) { // Verify signature if (!webhookValidator.verifySignature(payload, signature)) { return ResponseEntity.status(401).body("Invalid signature"); } // Put into message queue messageQueue.send("webhook-events", payload); // Return immediately return ResponseEntity.ok("OK"); }

Batch Queries

If you need to query multiple transactions, you can use batch queries to reduce the number of API calls.

public class BatchQueryService { /** * Batch query transactions */ public List<TransactionDetail> batchQuery(List<String> transactionIds) { List<TransactionDetail> results = new ArrayList<>(); // Query in batches (max 50 per batch) for (int i = 0; i < transactionIds.size(); i += 50) { List<String> batch = transactionIds.subList( i, Math.min(i + 50, transactionIds.size()) ); // Concurrent queries List<CompletableFuture<TransactionDetail>> futures = batch.stream() .map(id -> CompletableFuture.supplyAsync(() -> queryTransaction(id), executorService)) .collect(Collectors.toList()); // Wait for all queries to complete futures.forEach(future -> { try { results.add(future.get()); } catch (Exception e) { log.error("Query failed", e); } }); } return results; } }

Avoid Frequent Polling

Don’t poll transaction status frequently; this wastes resources and may trigger rate limiting.

// Don't do this while (true) { QueryResponse response = client.query(request); if (isFinalStatus(response.getData().getTransactionStatus())) { break; } Thread.sleep(1000); // Query once per second }

Configure Webhook URL to let SUNBAY proactively notify transaction results:

SaleRequest request = SaleRequest.builder() .amount(amount) .notifyUrl("https://your-domain.com/webhook/payment") // Configure Webhook .build();

If you must poll, use exponential backoff algorithm:

public TransactionDetail waitForResult(String transactionId, int maxRetries) { int retries = 0; long waitTime = 2000; // Initial wait 2 seconds while (retries < maxRetries) { QueryResponse response = client.query( QueryRequest.builder() .transactionId(transactionId) .build() ); String status = response.getData().getTransactionStatus(); if (isFinalStatus(status)) { return response.getData(); } // Wait then retry Thread.sleep(waitTime); // Exponentially increase wait time: 2s, 4s, 8s, 16s... waitTime = Math.min(waitTime * 2, 60000); // Max wait 60 seconds retries++; } throw new TimeoutException("Transaction timeout"); }

Performance Optimization Checklist

SDK Usage

  • Use official SDK (built-in optimizations)
  • Reuse SDK client instances (don’t create new instance each time)

Caching Strategy

  • Cache query results for final state transactions
  • Cache merchant configuration information
  • Don’t cache transaction status in processing

Webhook Processing

  • Webhook processing returns 200 quickly
  • Use asynchronous processing or message queues
  • Implement idempotency control

Query Optimization

  • Use Webhook instead of frequent polling
  • Use exponential backoff algorithm when polling
  • Control concurrency when batch querying
Last updated on