2

I am trying to make a SOAP request to a remote SOAP Server using the Savon gem in rails. The SOAP Server is replicated on three instances with different IP Addresses, i.e. XXX.XXX.XXX.1, XXX.XXX.XXX.2 and XXX.XXX.XXX.3.

I am able to explicitly define the savon client endpoint using one of the above ip addresses like so:

Savon.client(
    endpoint: "http://XXX.XXX.XXX.1:15043/enmac/SOAP",
    namespace: '',
    convert_request_keys_to: :camelcase,
    env_namespace: 'SOAP-ENV',
    namespace_identifier: nil,
    log: true,
    log_level: :info,
    pretty_print_xml: true,
    read_timeout: 90,
    open_timeout: 90,
    headers: {
        "Accept-Encoding" => "gzip"
    }
)

The problem with the above sample code is that when the SOAP Server instance with IP Address XXX.XXX.XXX.1 is down then my services goes down as well.

What I am actually looking for is an approach that will make sure that when SOAP Server instance XXX.XXX.XXX.1 is down then XXX.XXX.XXX.2 takes over etc.

Below is what I tried but couldn't get it to work properly:

  1. I have a database table with all the SOAP Servers instances populated by IP address with only a single of them with a status of active

  2. I have a the following method that shift to then next server:

      def shift_oms_server
          @oms_server = OmsServer.where(status: true).first
          case @oms_server.ip_address.to_s
              when 'XXX.XXX.XXX.1'
                @oms_server.update_attribute(:status, false)
                @next_oms_server = OmsServer.where(ip_address: 'XXX.XXX.XXX.2').first
                @next_oms_server.update_attribute(:status, true)
              when 'XXX.XXX.XXX.2'
                @oms_server.update_attribute(:status, false)
                @next_oms_server = OmsServer.where(ip_address: 'XXX.XXX.XXX.3').first
                @next_oms_server.update_attribute(:status, true)
              when 'XXX.XXX.XXX.3'
                @oms_server.update_attribute(:status, false)
                @next_oms_server = OmsServer.where(ip_address: 'XXX.XXX.XXX.1').first
                @next_oms_server.update_attribute(:status, true)
          end
      end
    
  3. Now I modify my Savon Client initialization like so:

        @oms_server = OmsServer.where(status: true).first
        Savon.client(
                endpoint: "http://#{@oms_server.ip_address.to_s}:15043/enmac/SOAP",
                namespace: '',
                convert_request_keys_to: :camelcase,
                env_namespace: 'SOAP-ENV',
                namespace_identifier: nil,
                log: true,
                log_level: :info,
                pretty_print_xml: true,
                read_timeout: 90,
                open_timeout: 90,
                headers: {
                    "Accept-Encoding" => "gzip"
                }
            )
    
       
  4. Finally wherever I make the SOAP Request call I will have something like a begin rescue block like so:

       begin
         # make soap server request
       rescue HTTPServerException => e
         shift_oms_server
         # make soap server request
       ensure
         shift_oms_server
         # make soap server request
       end
      

Forgive my English. The approach above didn't work for me. I will be happy if someone could enlighten me where I went wrong with the above approach or provide a direction to a more simpler and efficient approach.

Ideally I would like to know if it is possible to have more than one endpoints defined using the Savon gem, if yes how?

Thanks in advance.

Tom Lord
  • 27,404
  • 4
  • 50
  • 77
Pledges
  • 83
  • 9
  • What do you mean by "didn't work"? Is there an error message? Is there some undesired behaviour? What behaviour are you seeing? – Tom Lord Jan 15 '18 at 09:14
  • 1
    Your `begin...rescue...ensure...end` implementation is a bit dodgy, though. Why are re-sending the SOAP request **in the `ensure` block**?? This will cause all requests to be sent at least twice. However, I can't be certain of any behaviour since you didn't provide a [mcve] of code. – Tom Lord Jan 15 '18 at 09:19
  • Thanks @TomLord, that is exactly what is happening ... the request is sent multiple times at least twice like you just mentioned. – Pledges Jan 15 '18 at 09:32
  • I have removed the ...ensure block but the code is still behaving the same. It sends the request multiple times. I was under the impression that it will only go into the rescue block when there a problem was encountered during the sending of the request. But it seems it always go into the rescue block. – Pledges Jan 15 '18 at 09:42
  • It *will* only go into the rescue block when an exception is raised. Again: Can you provide a [mcve]? Exactly what behaviour are you seeing? – Tom Lord Jan 15 '18 at 09:56
  • I also don't understand what behaviour you'd expect if **all** SOAP servers go down? Logically, I'd say you should round-robin all three servers then abort; but your code's logic appears to be "try one, if that fails try a second one, then give up"?? – Tom Lord Jan 15 '18 at 10:12
  • I have fixed the code now, its working as expected [at least not as efficient or optimal ;)] .... thanks @TomLord for the advise, I needed to remove the ....ensure ...block. The reason why it was still misbehaving after the first attempt was due to some block of code doing the same thing somewhere. – Pledges Jan 15 '18 at 13:33
  • For what it's worth (although I'm still hesitant to submit a proper answer without seeing a [mcve]), a better implementation would be to do something like: `attempts = 0; begin; attempts += 1; make_soap_request; rescue; shift_oms_server && retry if attempts < 3; end` – Tom Lord Jan 15 '18 at 14:38

0 Answers0