You've heard of word ping or latency in network based applications. It's the time an application takes to respond to requests. For example, you're making a search on google. Your successful search will have following steps:
- In search bar, you enter some text
- Hit enter
- Request is being processed
- Response/results appear on webpage
Latency is the time it takes from step-2 to step-4.
Problem
In this blog, we will learn how to add a ping/latency time tool to our rails app. After setting this tool up, we will be able to monitor ping time for our rails app. The basic idea is to see how fast/slow our app is working.
Solution
Here is a prerequisite before we start adding this.
- Rails App running with webpacker (rails version should be >=5)
- Webpacker added
Let’s assume we have a rails app working with rails version => 5 and webpacker is added. Here’s how we will add this ping tool:
1-Add Stimulus
Run this command to add stimulus
Yarn add stimulus
Once it’s installed, use webpack to import it to the application. We will do this in app/javascript/packs/application.js
. In javascript directory, create controllers folder and then add index.js
there. Then reference this folder inside application.js
. This is how your index.js
will look like
import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"
const application = Application.start()
const context = require.context(".", true, /\.js$/)
application.load(definitionsFromContext(context))
2- Add turbo-rails and redis
To setup turbo-rails
, use following commands
bundle add turbo-rails
rails turbo:install
rails turbo:install:redis
Now we’re all set and ready to use it. Let’s generate a PingsController
with following command.
rails g controller ping
Let’s add #pong
action which renders plain text response with PONG
class PingController < ApplicationController
def pong
render status: :ok, body: "PONG"
end
end
Let’s add a /ping
endpoint routed to the #pong
action like this:
get “/ping”, to: “ping#pong”, as: “ping”
Let’s create a form now in app/views/shared/_ping.html.erb
to hit this rout.
<div data-controller="ping" >
<%= form_tag ping_path, method: :get, data: { action: "turbo:before-fetch-request->ping#pauseRequest turbo:submit-end->ping#measureLatency", "ping-target": "pingForm" } do %>
<%= button_tag "Ping" %>
<% end %>
<span data-ping-target="latency"></span>
</div>
Let’s create a homepage and add this partial their so it would be usable from the homepage. First, let’s create HomeController
with show
action.
rails g controller home show
Now make this show action as root action in route.rb
root to: “home#show”
Now render the form partial on show page
Add following code in app/views/home/show.html.erb
<%= render "shared/ping" %>
Next step is to measure the time latency now.
For this, we need to generate a stimulus controller.
rails g stimulus ping
And then let’s define the getters and setters we need to serve our purpose. We have a measureLatency()
fucntion that will measure the latency. Then there's a displayLatency()
function that will display latency on page every second. All of this code will go in app/javascript/controllers/ping_controller.js
as below.
import { Controller } from "stimulus";
export default class extends Controller {
static targets = ["pingForm", "latency"]
pauseRequest(event) {
event.preventDefault();
setTimeout(() => this.saveRequestTime());
event.detail.resume();
}
saveRequestTime() {
this.requestTime = new Date().getTime();
}
measureLatency() {
this.saveResponseTime();
this.latency = this.responseTime - this.requestTime;
console.log(`${this.latency} ms`);
this.displayLatency()
setTimeout(() => this.ping(), 1000)
}
displayLatency() {
this.latencyTarget.textContent = this.latency + " ms"
}
saveResponseTime() {
this.responseTime = new Date().getTime();
}
ping() {
this.pingFormTarget.requestSubmit()
}
get requestTime() {
return this._requestTime;
}
set requestTime(requestTime) {
this._requestTime = requestTime;
}
get responseTime() {
return this._responseTime;
}
set responseTime(responseTime) {
this._responseTime = responseTime;
}
get latency() {
return this._latency;
}
set latency(latency) {
this._latency = latency;
}
}
If we submit the form ping time will be printed after each second like in this picture.
Discussion
This is how you can tell the end user about the latency time. It is more helpful when you're working to scale your app and improving the app performance. To make the UI better, you can print a graph as well.
A simple Rails ping app is here in this Repo
Top comments (0)