2 Replies Latest reply on Dec 19, 2014 9:46 AM by Brendan Higgins

    Ruby Model Exceptions

    Brendan Higgins

      Quick question that should probably be easily answered by someone.

       

      I have been developing a JavaScript app and RhoConnect application.  The JavaScript RhoConnect performance has been abominable when requests outnumber the number of cores on your server.  We have traced the issue down and are working with Zebra for a fix.

       

      However in the meantime, we are trying to rewrite the RhoConnect piece in Ruby (we have no in-house Ruby experience).  Since there is no business logic in the RhoConnect piece, it really isn't too hard.

       

      The issue I am having is about raising and handling errors.  The back-end API will send an error message back if, for instance, a create cannot completed (missing information, etc.).  I want to take that error and raise it back to the application.  I am able to do that successfully, but the RhoConnect console produces a stack trace that makes me believe I should be handling the error differently.

       

      Basically, in the RhoConnect app I will do the following:

       

      raise Rhoconnect::Model::Exception.new(json_data['errorMessage'].to_s);

       

      And the console logs the following -- Is this normal?

       

      [7124][10:40:42.979 AM 2014-12-17] Model raised create exception: AIK9098 is not in the current transfer file.

      [7124][10:40:42.980 AM 2014-12-17] .../models/ruby/transfer_detail.rb:82:in `rescue in create'

      .../models/ruby/transfer_detail.rb:62:in `create'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes.rb:17:in `block in registered'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:97:in `call'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:97:in `_process_create'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:200:in `block (3 levels) in _process_cud'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:175:in `each'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:175:in `block (2 levels) in _process_cud'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:163:in `each'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:163:in `block in _process_cud'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:156:in `each'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:156:in `_process_cud'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:90:in `block in _measure_and_process_cud'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/stats/record.rb:54:in `update'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:88:in `_measure_and_process_cud'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:75:in `create'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:69:in `block in run_cud'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:68:in `each'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:68:in `run_cud'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/engine.rb:29:in `do_cud'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/runner.rb:27:in `run'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/execute_methods.rb:65:in `block in _run_cud_handler'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/server.rb:109:in `catch_all'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/execute_methods.rb:64:in `_run_cud_handler'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/handler/changes/execute_methods.rb:9:in `execute_cud_handler'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/server.rb:135:in `block in execute_api_call'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/server.rb:109:in `catch_all'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/server.rb:131:in `execute_api_call'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/server.rb:280:in `block in api4'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1603:in `call'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1603:in `block in compile!'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:966:in `[]'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:966:in `block (3 levels) in route!'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:985:in `route_eval'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:966:in `block (2 levels) in route!'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1006:in `block in process_route'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1004:in `catch'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1004:in `process_route'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:964:in `block in route!'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:963:in `each'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:963:in `route!'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1076:in `block in dispatch!'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1058:in `block in invoke'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1058:in `catch'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1058:in `invoke'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1073:in `dispatch!'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:898:in `block in call!'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1058:in `block in invoke'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1058:in `catch'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:1058:in `invoke'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:898:in `call!'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:886:in `call'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/middleware/current_user.rb:14:in `call'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/middleware/current_app.rb:12:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/session/abstract/id.rb:225:in `context'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/session/abstract/id.rb:220:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:114:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:91:in `block in new'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/middleware/stats.rb:21:in `call'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/middleware/stats.rb:21:in `call'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/middleware/body_content_type_parser.rb:31:in `call'

      ...gems/1.9.1/gems/rhoconnect-4.1.0/lib/rhoconnect/middleware/x_domain_session_wrapper.rb:25:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/static.rb:119:in `call'

      ...gems/1.9.1/gems/rack-protection-1.5.3/lib/rack/protection/xss_header.rb:18:in `call'

      ...gems/1.9.1/gems/rack-protection-1.5.3/lib/rack/protection/path_traversal.rb:16:in `call'

      ...gems/1.9.1/gems/rack-protection-1.5.3/lib/rack/protection/json_csrf.rb:18:in `call'

      ...gems/1.9.1/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'

      ...gems/1.9.1/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'

      ...gems/1.9.1/gems/rack-protection-1.5.3/lib/rack/protection/frame_options.rb:31:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/nulllogger.rb:9:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/head.rb:11:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:114:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:91:in `block in new'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/show_exceptions.rb:21:in `call'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/show_exceptions.rb:21:in `call'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:180:in `call'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:2014:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/urlmap.rb:65:in `block in call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/urlmap.rb:50:in `each'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/urlmap.rb:50:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/lint.rb:49:in `_call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/lint.rb:37:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/showexceptions.rb:24:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/commonlogger.rb:33:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:114:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/commonlogger.rb:14:in `call'

      ...gems/1.9.1/gems/sinatra-1.4.5/lib/sinatra/base.rb:217:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:91:in `block in new'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/chunked.rb:43:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/chunked.rb:43:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:114:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:91:in `block in new'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/content_length.rb:14:in `call'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/content_length.rb:14:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:114:in `call'

      ...gems/1.9.1/gems/async-rack-0.5.1/lib/async_rack/async_callback.rb:91:in `block in new'

      ...gems/1.9.1/gems/thin-1.6.2/lib/thin/connection.rb:86:in `call'

      ...gems/1.9.1/gems/thin-1.6.2/lib/thin/connection.rb:86:in `block in pre_process'

      ...gems/1.9.1/gems/thin-1.6.2/lib/thin/connection.rb:84:in `catch'

      ...gems/1.9.1/gems/thin-1.6.2/lib/thin/connection.rb:84:in `pre_process'

      ...gems/1.9.1/gems/thin-1.6.2/lib/thin/connection.rb:53:in `process'

      ...gems/1.9.1/gems/thin-1.6.2/lib/thin/connection.rb:39:in `receive_data'

      ...gems/1.9.1/gems/eventmachine-1.0.3-x86-mingw32/lib/eventmachine.rb:187:in `run_machine'

      ...gems/1.9.1/gems/eventmachine-1.0.3-x86-mingw32/lib/eventmachine.rb:187:in `run'

      ...gems/1.9.1/gems/thin-1.6.2/lib/thin/backends/base.rb:73:in `start'

      ...gems/1.9.1/gems/thin-1.6.2/lib/thin/server.rb:162:in `start'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/handler/thin.rb:16:in `run'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/server.rb:264:in `start'

      ...gems/1.9.1/gems/rack-1.5.2/lib/rack/server.rb:141:in `start'

      ...gems/1.9.1/gems/rack-1.5.2/bin/rackup:4:in `<top (required)>'

      .../ruby/bin/rackup:23:in `load'

      .../ruby/bin/rackup:23:in `<main>'

        • Re: Ruby Model Exceptions
          Jon Tara
          I have been developing a JavaScript app


          Can you confirm that what you mean here is that you have been developing a Rhodes application, and you are using the Javascript APIs? Or do you mean something else? (Like, you are using node.js on your server?)

          However in the meantime, we are trying to rewrite the RhoConnect piece in Ruby

          What "RhoConnect piece"? On your server or in the Rhodes app?

           

          The JavaScript RhoConnect performance has been abominable when requests outnumber the number of cores on your server.

          Do you mean that you make multiple outstanding requests from a single client, or do you mean that multiple clients hit the server in rapid succession?

           

          I want to take that error and raise it back to the application.  I am able to do that successfully, but the RhoConnect console produces a stack trace that makes me believe I should be handling the error differently.

          Which "application"? Your mobile Rhodes app, or your server RhoConnect code?

           

          What you show is normal, if you didn't write any code to catch the exception! Did you? If not, it's just going to keep going up the stack until it it's caught, if at all.

           

          The back-end API will send an error message back if, for instance, a create cannot completed (missing information, etc.).

          And does that part work? Does it send an error message back? What do you mean by "back end API"? Something that RhoConnect server is talking to?

            • Re: Ruby Model Exceptions
              Brendan Higgins

              Hi Jon, thanks for you interest.

               

              I will address my main area interest for the question first, then I am more than happy to elaborate on the other things.  Sorry, I wasn't clear, even though I was posting in the RhoConnect area, I guess I should have reiterated it -- this is all about the server side.

              What you show is normal, if you didn't write any code to catch the exception! Did you? If not, it's just going to keep going up the stack until it it's caught, if at all.

              Our data and a lot of business logic is stored in our legacy backend system.  Our backend business logic executes via a RESTful API from RhoConnect.  If the CUD (create, update, and delete) operations are not valid based on that backend logic, we need to send the error back through to the RhoMobile application, therefore I have no real desire to handle any rescue operations on the RhoConnect server (at least this is my assumption based how it worked with node.js -- but I am open to alternatives) because in all likelihood the user in RhoMobile will need to "fix" the data to perform the CUD operation(s).  I simply just want to raise the error up to the RhoMobile app and have the RhoMobile app handle the situation.  However when I raise the error in RhoConnect, which does properly send along the create-error, delete-error, and/or update-error for RhoMobile to handle, it throws a disconcerting (for a newbie Ruby developer) stack trace up on the server, hence my question.

               

              When I do this:

               

              raise Rhoconnect::Model::Exception.new(json_data['errorMessage'].to_s);

               

              The stack trace rears its ugly head (to a developer anyway).  Is there a better way to get that error back to the RhoMobile app with the correct create-error, delete-error, and/or update-error to avoid the disconcerting stack trace?

               

              Previously, before the rewrite, when the error was handled with node.js, there was no such stack trace.

               

              Now on to the other questions...

              Can you confirm that what you mean here is that you have been developing a Rhodes application, and you are using the Javascript APIs? Or do you mean something else? (Like, you are using node.js on your server?)

              Yes, we have been using the production stack, so yes, node.js for the adapters on the server.  But, again, the performance is abominable, so we are abandoning the JS interfaces.

               

              What "RhoConnect piece"? On your server or in the Rhodes app?

              The RhoConnect adapters. 

               

              Do you mean that you make multiple outstanding requests from a single client, or do you mean that multiple clients hit the server in rapid succession?

              Sure -- it doesn't matter, it will happen in either case.  As long as the number of requests exceeds the number of cores of the server, the condition exists.  And yes, we have set use_async_model to false in config.ru.

               

              Which "application"? Your mobile Rhodes app, or your server RhoConnect code?

              The RhoMobile/Rhodes app (see above, too).

               

              And does that part work?  Does it send an error message back?

              Yes the error does go all the way back to the RhoMobile application, but again, it is the disconcerting stack trace I am concerned with (see above).

               

              What do you mean by "back end API"? Something that RhoConnect server is talking to?

              Yes, via RESTful services.