I run a Morse Code website that allows users to convert text into Morse code and decode Morse messages through an interactive web interface, and I recently started moving some of the backend functionality into a Ruby on Rails application. The translation itself is extremely lightweight because it mainly consists of looking up characters in a Morse mapping and returning the corresponding result. However, when several users access the application at the same time, response times occasionally increase significantly even when each individual request contains only a short piece of text. I am trying to understand why such a simple operation can become noticeably slower when concurrent requests reach the Rails application.
The frontend sends requests to the Rails backend for some translation-related operations, while other interface features such as audio playback continue to run directly in the browser. During testing with only a few users, the application responds almost instantly and there is no obvious performance problem. When I simulate a larger number of simultaneous requests, however, response times begin increasing and some requests appear to wait before being processed. The server CPU does not always appear to be saturated, which makes me suspect that the bottleneck may be related to Rails request handling, Puma configuration, database access, or connection pooling rather than the Morse Code algorithm itself.
I have already checked the translation code and confirmed that it does not perform any particularly expensive computation or external API calls for each request. The Morse mapping is kept in memory, so I would not expect the lookup operation itself to consume meaningful resources even under considerable traffic. I am also using a relatively simple controller action, but I am unsure whether there are Rails-specific request lifecycle costs that become more visible when many small requests arrive simultaneously. I would like to determine whether I should first investigate Puma worker and thread settings, Rails database connection pools, middleware, or another part of the request pipeline.
Another complication is that the website is designed to feel real time because users expect the Morse output to appear almost immediately while interacting with the translator. Introducing aggressive batching or asynchronous processing on the frontend could make the application feel less responsive, while sending every small interaction to the backend may create unnecessary request volume. I am therefore trying to find the right Rails architecture for handling lightweight, frequent requests without introducing avoidable overhead. I am particularly interested in whether a Rails API-only setup, background processing, caching, or keeping more translation logic entirely client-side would be considered the better approach.
I have also considered using caching because the same characters and common Morse combinations are translated repeatedly, but I am not sure whether caching individual translation results would provide any meaningful benefit given how inexpensive the underlying operation is. Instead, I suspect the more important optimization may involve reducing unnecessary database queries and ensuring that Rails is not creating excessive connections or waiting on limited resources during traffic spikes. I would like to benchmark the application properly rather than making changes based only on CPU usage or individual request timings. Any recommendations for profiling a Rails application under concurrent lightweight workloads would be particularly useful.
Has anyone encountered a similar performance pattern in a Rails application where individual requests are extremely cheap but response times increase significantly as concurrency rises? I would appreciate advice on how to systematically identify whether the bottleneck is Puma concurrency, database connection pooling, middleware, application code, or server configuration before attempting a major architectural change. For a Morse Code application where low latency is important but the actual computation is trivial, I would also like to know whether experienced Rails developers would keep the translation entirely client-side and reserve Rails for persistence and account-related functionality. Any guidance on benchmarking, profiling, and designing this type of workload would be greatly appreciated. Sorry for long post!