Case studies · Travel media

Holiday Weather: off Heroku, onto serverless AWS — and 4× faster at the tail

An undocumented Java "microservice" estate on Heroku became a TypeScript serverless platform on AWS. Median response time fell from 334 ms to 207 ms and the slowest request from 2.3 s to 0.3 s.

Service
AWS configuration & scaling
Industry
Travel media
Client
Holiday Weather ↗
Year
2020
334 → 207 msmedian response
2.3 s → 0.3 sslowest request
−77%p90 latency
The problem

Holiday Weather — a site serving weather forecasts and averages for holiday destinations — ran as a set of Java/Spring "microservices" on Heroku with no documentation, tangled cross-dependencies and little support from the original team. Every change was risky, and the 90th-percentile response time was over 1.3 seconds.

What we did

We proposed a lift-and-shift to AWS ECS first, then made the case for a rewrite instead — TypeScript on Lambda, DynamoDB with streams, SQS, S3 and a Redis cache in front of the site — and built it. Weather feeds arrive by FTP on a schedule, locations are managed through an admin API, and every stage is observable in CloudWatch.

What changed

The new platform serves a median request in 207 ms (was 334 ms) and its slowest request in 302 ms (was 2,290 ms) — and once it was stable, we replaced the inherited FTP downloads with the provider's API.

The starting point

Holiday Weather gives UK holidaymakers live weather, forecasts and monthly averages for hundreds of destinations — Majorca, Tenerife, the Maldives, Cancún. Behind the site sat a Java (Spring) application hosted on Heroku, split into “microservices” that were more tangled than modular: undocumented, cross-dependent, backed by Redis, and supported only sporadically by the team that had built it.

For the owners this meant three problems at once: nobody could safely change the system, the platform cost more to run than it should, and users felt it — the 90th-percentile response time was 1.3 seconds and the slowest requests took over two.

Two proposals

Proposal one — lift and shift. Containerise the existing Java services and run them on AWS ECS. Lowest risk on paper, but it would have moved the undocumented complexity to a new bill without removing it.

Proposal two — rewrite for the platform. Re-implement the data pipeline and API in TypeScript on AWS Lambda, store locations and forecasts in DynamoDB and use DynamoDB Streams to fan out changes, decouple the stages with SQS, archive raw feeds to S3, and keep a Redis cache in front of the website. More work up front; a system the client’s team could actually understand and operate afterwards.

The client chose the rewrite.

The final architecture

Stage What runs
Ingest Forecast data pulled from the provider’s API (originally scheduled downloads of zipped files over FTP — see below)
Locations An admin API defines which destinations exist; they live in DynamoDB
Processing Lambda functions parse the feeds, filter them against the location list and push work onto SQS
Storage Processed forecasts in DynamoDB; raw files archived to S3
Serving The website reads from a Redis cache that is refreshed from the pipeline

Everything is infrastructure-as-code and every stage reports to CloudWatch, so a bad feed or a slow provider shows up as a graph, not a customer complaint.

The numbers

Benchmarked with the same load against both platforms (ApacheBench, connection times in ms):

Heroku (old) AWS (new)
Mean total 521 216
Median 334 207
90th percentile 1,316 297
99th percentile 2,290 302
Longest request 2,290 302

The tail is the story: the slowest request on the new platform is faster than the median on the old one.

And then we asked the right question

The pipeline still began with scheduled downloads of zipped files from the data provider’s FTP server — because that was how it had always been done. Once the platform was stable we went back to the provider and asked what else they offered. They had a proper API. We replaced the FTP polling with direct API integration: forecasts arrive as they are published instead of on a timer, the ingest code shrank to a fraction of its size, and one more moving part disappeared from the on-call list.

The lesson we carry into every migration since: rebuild the platform, but also question the inputs you inherited.

← More case studies

Contact

A consultation with one of our engineers

Tell us what you are dealing with. Within two working days you get a concrete proposal with scope and price.

  • Reply from a senior engineer or lead auditor, not an account manager
  • Fixed scope and price before any work starts
  • ISO 9001 and ISO 27001 certified processes, NDA on request