I need to do request on remote service after rendering the page
My controller:
after_filter :remote_action, only: :update
def update
#res = MyService.do_action foo, bar
return render json: #res[:json], status: #res[:status] unless #res[:success]
end
def remote_action
# There is remote http request
end
I need to call remote_action method after rendering the page
after_filter is run after the template has been converted into html, but before that html is sent as a response to the client. So, if you're doing something slow like making a remote http request, then that will slow your response down, as it needs to wait for that remote request to finish: in other words, the remote request will block your response.
To avoid blocking, you could fork off a different thread: have a look at
https://github.com/tra/spawnling
Using this, you would just change your code to
def remote_action
Spawnling.new do
# There is remote http request
end
end
The remote call will still be triggered before the response is sent back, but because it's been forked off into a new thread, the response won't wait for the remote request to come back, it will just happen straight away.
You could also look at https://github.com/collectiveidea/delayed_job, which puts jobs into a database table, where a seperate process will pull them out and execute them.
Related
I'm trying to create an SPA with react frontend and a rails API, and I managed to stop the request from the javascript side, with that in mind, I notice that even if I cancel the request, the rails server stills performs the stuff inside the controller.
def index
#dashboards = Dashboard.all
# Rest of controller logic, like calls to an external API
render json: json_response(#dashboards)
end
Is there a way to catch that the xhr request was cancelled so I can do something like this:
def index
#dashboards = Dashboard.all
if request.cancelled? throw :abort
# It should not matter since request was cancelled in the frontend
render json: json_response(#dashboards)
end
No, sorry, even with a stateful connection like websockets there's no way to reliably detect when that connection is dropped.
How can I send a message when the job finishes successfully? I would like to send the message and show it in a swal in javascript when the work finishes correctly, but I do not know how to do this, any suggestions?
I do not need to do anything other than send a message
class CompileProjectJob < Struct.new(:url)
def perform
end
def success(job)
#send message when the work is successful
end
end
At the end of perform method queue new delayed job for sending the message
class CompileProjectJob < Struct.new(:url)
def perform
# the code here of this job
# queue new job
end
end
the code of the perform method is executed sequentially as any regular code
Update
to send the message to the front end there are two ways (push and pull) more info
- push: using web sockets you push the message from the backend to the front end
- pull: the front end sends requests every certain period to check if the backend has a new data
and you can use any of these techniques to solve the problem
if you used pulling you will make the job update a data store as an example Redis or mysql. the front end will send a request every interval to check for the new data in some scenarios this will be a better solution but i think you are looking for the other technique
pushing:
here you can use something like active cable https://guides.rubyonrails.org/action_cable_overview.html
or a third party like pusher https://www.pusher.com/tutorials/realtime-table-ruby-rails
the main idea here your frontend app will open a websocket connection with your server. this socket will stay opened and listen for any updates from the backend through a channel so when you send the update after finishing the job through this channel it will be received by the front end so you can add code to show the message
I have following actions in a Test controller:
def run
while true do
# code
end
end
def stop
# stop the run action
end
how can stop action be implemented to halt the run action?
Because a client will wait for a response from a server, you can't have a loop in an endpoint that waits for another endpoint to be called.
In this case, a client will visit /test/run, but since the server won't return anything until the loop finishes, the client will just keep waiting.
This means (unless you specifically configured your webserver to do so), that another connection can't be made to the server to reach the test/stop endpoint.
If you must have a "job" that runs and be cancel-able by an endpoint, turn it into an actual background task.
(I know it's not best practice, but I'm still wondering if there's a way to do it)
I have a controller action that has a moderately long-running part (~30 seconds). I'd like to respond to the HTTP request (so that it closes), run the part that takes time, then use something like Pusher to notify that it's successful (last part is done, but here for context).
Something like this:
def some_action
if action_should_succeed?
head :no_content
else
render text: "Some error message", status: :unproccessable_entity
end
# Connection is now closed and the client has received the HTTP response
do_long_thing()
send_notification()
end
I know that the "correct" way to do this is to have a job queue and a worker process, but while this is the only action with this kind of delayed processing, I'd prefer not to add all that. Any ideas?
I have an API centric application (/api/v1/users) it simply return all users restfully with JSON format.
My problem is, if I call that route on the controller, it returns "Timeout::Error"
What is the problem?
class BaseController < ApplicationController
def index
return HTTParty.get('http://localhost:3000/api/v1/users').body
end
end
Update
users_controller.rb (/api/v1/users)
application_controller.rb
https://gist.github.com/4359591
Logs
http://pastie.org/5565618
If I understand correctly, you have an API end-point, at /api/v1/users, and your BaseController#index is calling that method?
If that is correct, inside the same rails process, and you are testing in development mode (as I can tell from your url), then you only have a single process running, which can only handle a single request at once. So if you start a request to BaseController#index, it will start another request to your own test-server, which is busy, and it will just wait until it times out.
If you want to test your API, I would look at a client tool like e.g. Postman.
HTH.