This is more or a testing helper than an answer, since the question doesn't provide enough details to narrow the issue down.
I wrote a simple test application using Plezi. Since I'm plezi's author it was easier for me than to learn your stack.
It works perfectly on my computer, 79ms for a ~3Mb file.
The ~3Mb roundtrip to Heroku took my system 3 seconds and went down to ~2.5 seconds after the TCP/IP warmup was complete...
...but my internet speeds are probably effecting the test (my reception is low at the moment, so I might be slow).
I'm not sure I can replicate the issue, but you can use the code in this answer to test your server.
If the roundtrip still takes longer than 10 seconds, it might be the EC2 stack. I don't think 10 seconds would be reasonable for ~500Kb.
On the other hand, if it's a shorter roundtrip, it might be either the way you tested your application or your Ruby stack... in which case, maybe the solution is to switch to plezi (or the iodine native websocket design).
You can paste the following code into config.ru
(remember you'll also need a gem file with the plezi
gem and possibly a Gemfile.lock
):
# The roundtrip html client
ROUNDTRIP_CLIENT = <<CLIENT_EFO
<html>
<head>
<script src = '/client.js'></script>
</head>
<body>
<input type='file' id='test_f' lable='file to upload'></input>
<button id='test_b'>run test</button>
<div id='output'></div>
<script>
var client;
window.onload = function (e) {
client = new PleziClient();
client.autoreconnect = true;
client.roundtrip = (e) => {
var d = new Date();
e.completed_at = d.getTime();
console.log(e);
document.getElementById('output').innerHTML += "<p>Test for " +
"<a href='" + e.data + "' target='_blank'>" + Math.round(e.data.length / 1024)+ "Kb encoded file</a>" +
" completed in " + (e.completed_at - e.time) + "ms</p>";
}
client.onopen = (e) => console.log("Websocket client open", e);
}
function run_test(e) {
console.log("File submitted.");
reader = new FileReader();
reader.onloadend = function(e)
{
console.log("File loaded, " + e.target.result.length + "bytes... starting test.")
var d = new Date();
client.emit({event: "roundtrip", data: e.target.result, time: d.getTime() });
}
reader.readAsDataURL(document.getElementById('test_f').files[0]);
return false;
}
document.getElementById('test_b').onclick = run_test;
</script>
</body>
</html>
CLIENT_EFO
# require plezi
require 'plezi'
# For security, Iodine limists websocket messages.
# We update the default limit from ~250Kb to ~4Mb.
# This replaces the commandline option: iodine -v -maxms 4194304
Iodine::Rack.max_msg_size = 4194304
# the roundtrip controller... quite simple.
class RoundTrip
# return the roundtrip client.
def index
ROUNDTRIP_CLIENT
end
# echo back the websocket message - we're just testing the round trip.
def on_message data
write data
end
end
# Set the plezi root route to the RoundTrip controller
Plezi.route '/', RoundTrip
# Set the client javascript route - I'm using it as a heler.
Plezi.route '/client.js', :client
# Set Rack to run the Plezi application
run Plezi.app
To run the code from the terminal, use the iodine
command (it will start the iodine
server, which Plezi requires.
EDIT
From the link to the git-repo (in the comments), I realized that the JSON is parsed by the server and then it is re-emitted.
To emulate this, I updated the example code.
This should be similar to what the code in the repo seems to do and it adds some time to the roundtrip, since the JSON parsing and re-formatting create copies of the data, which requires memory allocation as well as CPU time.
The only change in the code is in the RoundTrip
controller class, but I'm pasting the whole thing for your copy+paste convenience.
Place the following code in your app.rb
file (remember to edit install.sh
to install the plezi
gem):
# The roundtrip html client
ROUNDTRIP_CLIENT = <<CLIENT_EFO
<html>
<head>
<script src = '/client.js'></script>
</head>
<body>
<input type='file' id='test_f' lable='file to upload'></input>
<button id='test_b'>run test</button>
<div id='output'></div>
<script>
var client;
window.onload = function (e) {
client = new PleziClient();
client.autoreconnect = true;
client.roundtrip = (e) => {
var d = new Date();
e.completed_at = d.getTime();
console.log(e);
document.getElementById('output').innerHTML += "<p>Test for " +
"<a href='" + e.data + "' target='_blank'>" + Math.round(e.data.length / 1024)+ "Kb encoded file</a>" +
" completed in " + (e.completed_at - e.time) + "ms</p>";
}
client.onopen = (e) => console.log("Websocket client open", e);
}
function run_test(e) {
console.log("File submitted.");
reader = new FileReader();
reader.onloadend = function(e)
{
console.log("File loaded, " + e.target.result.length + "bytes... starting test.")
var d = new Date();
client.emit({event: "roundtrip", data: e.target.result, time: d.getTime() });
}
reader.readAsDataURL(document.getElementById('test_f').files[0]);
return false;
}
document.getElementById('test_b').onclick = run_test;
</script>
</body>
</html>
CLIENT_EFO
# require plezi
require 'plezi'
# For security, Iodine limists websocket messages.
# We update the default limit from ~250Kb to ~4Mb.
# This replaces the commandline option: iodine -v -maxms 4194304
Iodine::Rack.max_msg_size = 4194304
# the roundtirp controller... quite simple.
class RoundTrip
@auto_dispatch = true
# return the roundtrip client.
def index
ROUNDTRIP_CLIENT
end
# Using Auto-Dispatch, the JSON is parsed and this event is invoked.
def roundtrip msg
# Hash results are automatically converted into JSON and emitted
msg
end
end
# Set the plezi root route to the RoundTrip controller
Plezi.route '/', RoundTrip
# Set the client javascript route - I'm using it as a heler.
Plezi.route '/client.js', :client
# Plezi will start automatically when the script exits
To run the code from the terminal, use the ruby app.rb
command, same as your repo does for the existing app.
While the old code simply offered and "echo" response, the new code (which looks almost the same) has a few more steps:
Using Auto-Dispatch, the Plezi framework now automatically parses the JSON and routes the event ("roundtrip") the the controller's method (roundtrip
).
The method receives a Hash with the parsed data and returns that Hash back to Plezi.
The framework collects the Hash, formats a JSON object and emits back the result (non String or Hash results are ignored)...
... this is similar to the repo's behavior.