Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Abubakar Ahmed reports that CrimeLens’s stress-test p95 latency fell from 36.64 seconds to 2.8 seconds after a bundle of backend and deployment changes. The improvement is substantial, but the reported final stress result still missed the configured two-second p95 threshold, and the spike test recorded 31 connection-refused errors. These are results from one author-reported test setup—not a production performance guarantee.

What CrimeLens is, and what the tests set out to find

CrimeLens is a crime-reporting, mapping, and analytics platform. Its workflows connect citizens, public users, police officers, and administrators; approved reports feed maps, statistics, trends, and geospatial searches. Ahmed describes its architecture as a PERN modular monolith: React and TypeScript on the client, Node.js and Express on the server, and PostgreSQL with PostGIS, hosted through Supabase.

The project’s k6 tests exercised normal API traffic, gradually increasing stress, sudden traffic spikes, and recovery. They included authentication, crime-report submissions, statistics, and geospatial endpoints. The goal was to establish a baseline, locate bottlenecks, make changes, and rerun the same scripts. Ahmed’s case study is available on DEV Community.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Where the baseline struggled

Under normal load, Ahmed reports an overall p95 response time of 5.13 seconds. In the stress run, p95 rose to 36.64 seconds and p99 to 41.61 seconds. The /api/stats/summary endpoint stood out as a bottleneck; the results also pointed to database connection-pool contention and requests waiting in queues.

These findings suggest distinct areas to investigate: expensive database work, contention for database connections, and the handling of requests while demand rises. They do not establish that any one issue alone caused the measured delays.

What Ahmed changed

The improvements formed a bundle across data access, request handling, operations, and deployment. Ahmed does not isolate the effect of each change, so the before-and-after results cannot show how much any individual tool or intervention contributed.

Database queries and geospatial work

  • Added PostgreSQL indexes and optimized frequently executed queries.
  • Improved PostGIS and geospatial query handling.
  • Added pagination to limit the amount of data returned per request.
  • Increased and monitored the database connection pool.

Caching and request controls

  • Introduced Redis cache-aside caching with time-to-live (TTL) settings and invalidation.
  • Added Redis-backed rate limiting.
  • Added request validation and sanitization.

Security, compression, and observability

  • Tightened Helmet and CORS settings.
  • Enabled gzip and Brotli compression.
  • Added Pino structured logs and request IDs, plus Prometheus metrics and Grafana dashboards.

Deployment and background work

  • Containerized the application with Docker and added Nginx as a reverse proxy.
  • Tested multi-instance load balancing.
  • Used BullMQ for Cloudinary deletion jobs.
  • Added CI/CD checks involving GitHub Actions, CodeQL, npm audit, Docker scanning, and Trivy.

What the before-and-after numbers show

The following figures are attributed to Ahmed’s article. Its page displays “Posted on Sep 22” without a year; 2026 is inferred from the site footer’s 2016–2026 copyright range. Ahmed says he reused the k6 scripts, but the architecture changed between runs.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Normal-load run

Measure Before After
Requests processed 24,667 53,972
Throughput 25.5 req/s 55.4 req/s
p50 latency 1,230 ms 25 ms
p95 latency 5,130 ms 655 ms
p99 latency 7,690 ms 1,540 ms
HTTP error rate 0.10% 0.006%

Stress run

Measure Before After
Requests processed 33,106 289,121
Throughput 32.3 req/s 282.2 req/s
p50 latency 8,170 ms 119 ms
p95 latency 36,640 ms 2,800 ms
p99 latency 41,610 ms 4,335 ms
HTTP errors 0 0

Although the stress-run p95 improved sharply, its final value remained above the configured two-second threshold. The zero HTTP errors in that run should not be read as evidence that every scenario was error-free.

Spike, recovery, and endpoint results

Measure Before After
Requests processed in spike/recovery scenario 4,997 51,198
Spike-phase p95 45,191 ms 2,964 ms
Recovery-phase p95 10,370 ms 202 ms
/api/stats/summary p95 8,050 ms 1,104 ms
Radius-search endpoint p95 2,200 ms 583 ms

The spike rerun also recorded 31 connection-refused errors at the local Nginx/Docker entry point. Ahmed identifies this as a remaining availability issue to investigate, rather than treating the faster recovery latency as a complete resolution.

How to interpret the results

The comparison supports a limited conclusion: in Ahmed’s setup, the rerun of the same k6 scripts after a broad set of changes processed more requests and reported lower latency across the listed scenarios and endpoints. It does not identify which change produced which portion of the improvement, or establish how the system would perform in another environment.

Ahmed conducted the tests on a local Windows machine. The baseline backend ran locally in Node.js development mode; the final run used Docker, Nginx, Redis, and application containers. Both used a remote Supabase PostgreSQL/PostGIS free-tier database and a relatively small dataset. Reusing scripts helps make the comparison useful, but the changed architecture and test conditions mean it is not a controlled, isolated test of a single optimization.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The measurements are author-reported, not independently reproduced benchmarks. Ahmed notes that production performance also depends on the hosting platform, database tier and region, network latency, available CPU and memory, and real dataset size. The results therefore should not be used as a prediction for another CrimeLens deployment or a different application.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A useful performance-improvement loop

The strongest transferable lesson is the measurement process, not a promise that the same tools will yield the same numbers. Ahmed describes it this way: “The real process was: Measure the existing system → identify bottlenecks → introduce targeted improvements → observe the system → rerun the same tests → compare the results -> find New Problems -> repeat”.

  1. Establish a baseline. Record workload, throughput, latency percentiles, errors, and endpoint-level behavior before changing the system.
  2. Find the bottleneck. Use endpoint results and operational signals to distinguish slow queries, connection contention, queueing, or other constraints.
  3. Choose changes that address observed problems. Avoid treating a cache, index, proxy, or monitoring tool as an improvement without evidence that it addresses a measured bottleneck.
  4. Rerun the workload and inspect the full result. Compare the same scenarios and metrics, while noting any changes to runtime, infrastructure, data, or network conditions.
  5. Follow up on remaining failures. A better latency percentile does not erase threshold misses or availability errors; treat them as separate issues to investigate.

For comparisons across systems, useful context includes hardware and runtime mode, database tier and location, dataset size, concurrency and duration, network conditions, and whether the software architecture changed. Without those details, a throughput or latency figure is easy to overgeneralize.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.