Selected case studies

The interesting part is usually the decision that came before the code.

These are simplified versions of real production work. Partner details and proprietary implementation details are intentionally omitted; the problems, decisions and outcomes are the useful part of the story.

01
Performance

40 → 200 RPS: improving the existing platform before scaling out.

The cashback platform was getting busier, and scaling out looked like the obvious answer. Before scaling out, the first step was to understand what the existing instances were actually spending time on.

Investigation

JVM and memory behavior, cache utilization, database work, asynchronous paths, threads and logging.

Engineering changes

JVM tuning, Caffeine + Redis multi-level caching, query optimization and asynchronous processing.

Result

Throughput improved from 40 to 200 requests/sec per instance, while production instances dropped from 14 to 8.

Engineering takeaway

Measure first. It is easy to buy more hardware; it is harder to find the constraint. In this case, the constraint was solvable in the application.

02
Platform architecture

Configuration became a product feature.

Cashback, lending, NPS and referral programmes kept asking for slightly different behavior. Releasing code for every variation would have made the platform harder to change over time.

Need

Business rules and campaign behavior had to change frequently without turning every change into another application release.

Approach

Reusable business-rule and campaign-management capabilities, with the right variability represented as configuration.

Scale

110+ concurrent campaigns and approximately 8M eligibility evaluations per day.

Engineering takeaway

Good configuration has a boundary. The goal is to make predictable change cheap, not to turn every business decision into a giant rules engine.

03
Integration architecture

One framework, 35 banking partners.

Partner integrations had common steps but partner-specific differences around certificates, encryption, validation and communication. That variation was placed behind a reusable framework.

Problem

Every new bank could otherwise create another round of custom integration and serviceability work.

Approach

A common integration and onboarding flow with partner variation handled through configuration and reusable execution components.

Result

The framework supported 35 banking partners and multiple TPAP integrations.

Engineering takeaway

When integrations share a shape, a good framework should remove repetition without pretending that every partner behaves identically.

04
Production troubleshooting

The application was slow. The database wasn’t the problem.

A slowdown showed up during peak traffic. There were no obvious exceptions or database alarms, and CPU and memory looked normal. The clue came from looking at thread dumps and Grafana together.

Signal

Request threads were waiting in the logging pipeline while Grafana showed elevated disk I/O wait.

Root cause

The primary Logback appender used neverBlock=false. Under higher traffic, the logging queue could fill and request threads could block while writing logs.

Fix

Logging configuration was changed and application performance recovered.

Engineering takeaway

Production performance is a system problem. The bottleneck can sit in a subsystem that was never part of the original business flow.

05
Operational automation

Stop asking someone to remember the campaign schedule.

A campaign that was meant to run during a recurring time window initially needed someone to activate and deactivate it manually.

Problem

Manual activation and deactivation created recurring operational work around the start and end of each campaign window.

Approach

Five parameters captured recurring-active state, start time, end time, frequency and frequency calculation.

Result

Daily, weekly and monthly recurrence patterns could be expressed through configuration, removing the manual step.

Engineering takeaway

Sometimes the best engineering improvement is not another service. It is making the system smart enough to remove a task that people keep repeating.

06
Preventive engineering

A cache miss we wanted to avoid.

Offer constructs lived in Redis with an approximately two-hour TTL. The concern was what could happen if the cache expired for many requests at roughly the same time during a busy period.

Risk

Many requests could miss Redis together and hit the database at once when the TTL expired.

Options

Distributed locking was considered, but slow database responses could leave application threads waiting.

Decision

A simple hourly cron on one server triggered an API that refreshed offers into Redis with a two-hour TTL.

Important context

This was preventive work, not a confirmed production incident. The choice favored simple, predictable operations over adding distributed locking complexity.

Internal endpoints, certificates, keys, partner details and proprietary architecture are intentionally omitted.