Multiple Threads?

I need to create a little client for a third party web service. The client should poll the service constantly. I need to monitor for new events (they don't have callbacks apparently...) so they keep the connection open for 15 seconds and returns nothing if nothing has happened. If an event happens then it returns when it actually happens. After returning I should immediately request again.

This is fine as long as I only need to poll for one customer (since one request only can check for one customer). The problem is that we need to poll this service for multiple customers at the same time and then I of course need threads.

I was thinking along the following lines (something is wrong with the threading parts, when I run it without threads it works so it is not the soap stuff that is wrong)

require 'soap/rpc/driver'

CreateSessionResponse = Struct.new(:response_code, :session_id, :host)

proxy = SOAP::RPC::Driver.new('url_to_service, 'urn:webservice')
[
  %w(createSession password name type tenant domain application),
  %w(getEvents sessionId)
].each do |signature|
  proxy.add_method(*signature)
end

class Client

  def initialize(name = "", password = "", type = "", tenant = "", domain = "", application = "")
    @name, @password, @type, @tenant, @domain, @application = name, password, type, tenant, domain, application
  end

  def run(proxy)
    thread = Thread.new {
      while true
        # log in to server and get a session id
        session = CreateSessionResponse.new(*proxy.createSession(@password, @name, @type, @tenant, @domain, @application))
        # fetch events. returns after 15 seconds if no new events
        events = proxy.getEvents(session.session_id)
        if events
          notify_stb(events)
        else
          puts "no new events" # never see's this
        end
      end
    }
    thread.join # without joining the program exits immediately
  end

  def notify_stb(events)
    puts "Notifying client with data #{events}" # never see's this
  end

end

puts "Starting..."
# when testing I only have data for one client, will be more later
clients = [["name", "pwd","","","domain","application"]].inject() {

result, client_data| result << Client.new(*client_data)}

clients.each { |client| client.run(proxy) }

It might be that I actually do requests. The service is remote and I don't have a chance to check if the requests are actually getting there (and there is also this 4:th of July in the States apparently...).

Can anyone see anything obviously wrong? I haven't really done anything with threads in Ruby before so...

Regards,

Marcus

Look at EventMachine in Rubyforge.

···

On 7/4/06, Marcus Andersson <m-lists@bristav.se> wrote:

I need to create a little client for a third party web service. The
client should poll the service constantly. I need to monitor for new
events (they don't have callbacks apparently...) so they keep the
connection open for 15 seconds and returns nothing if nothing has
happened. If an event happens then it returns when it actually happens.
After returning I should immediately request again.

This is fine as long as I only need to poll for one customer (since one
request only can check for one customer). The problem is that we need to
poll this service for multiple customers at the same time and then I of
course need threads.

I was thinking along the following lines (something is wrong with the
threading parts, when I run it without threads it works so it is not the
soap stuff that is wrong)

require 'soap/rpc/driver'

CreateSessionResponse = Struct.new(:response_code, :session_id, :host)

proxy = SOAP::RPC::Driver.new('url_to_service, 'urn:webservice')
[
  %w(createSession password name type tenant domain application),
  %w(getEvents sessionId)
].each do |signature|
  proxy.add_method(*signature)
end

class Client

  def initialize(name = "", password = "", type = "", tenant = "",
domain = "", application = "")
    @name, @password, @type, @tenant, @domain, @application = name,
password, type, tenant, domain, application
  end

  def run(proxy)
    thread = Thread.new {
      while true
        # log in to server and get a session id
        session =
CreateSessionResponse.new(*proxy.createSession(@password, @name, @type,
@tenant, @domain, @application))
        # fetch events. returns after 15 seconds if no new events
        events = proxy.getEvents(session.session_id)
        if events
          notify_stb(events)
        else
          puts "no new events" # never see's this
        end
      end
    }
    thread.join # without joining the program exits immediately
  end

  def notify_stb(events)
    puts "Notifying client with data #{events}" # never see's this
  end

end

puts "Starting..."
# when testing I only have data for one client, will be more later
clients = [["name", "pwd","","","domain","application"]].inject() {
>result, client_data| result << Client.new(*client_data)}
clients.each { |client| client.run(proxy) }

It might be that I actually do requests. The service is remote and I
don't have a chance to check if the requests are actually getting there
(and there is also this 4:th of July in the States apparently...).

Can anyone see anything obviously wrong? I haven't really done anything
with threads in Ruby before so...

Regards,

Marcus

Francis Cianfrocca skrev:

Look at EventMachine in Rubyforge.

On Windows XP:

C:\Downloads>gem install eventmachine-0.5.3-mswin32.gem
Attempting local installation of 'eventmachine-0.5.3-mswin32.gem'
ERROR: Error installing gem eventmachine-0.5.3-mswin32.gem[.gem]: buffer error

I looked in the readme. There is an example there on how to create a server. How would I use EventMachine to work as a client app?

Regards,

/Marcus

Marcus Andersson skrev:

Francis Cianfrocca skrev:

Look at EventMachine in Rubyforge.

On Windows XP:

C:\Downloads>gem install eventmachine-0.5.3-mswin32.gem
Attempting local installation of 'eventmachine-0.5.3-mswin32.gem'
ERROR: Error installing gem eventmachine-0.5.3-mswin32.gem[.gem]: buffer error

Also tried to do

gem install eventmachine

But then it tried to build native extensions and I don't have a build environment for C on my WinXP setup.

/Marcus

Your application sounds in many ways like a "server" in the sense that it
needs to maintain a lot of open connections (the fact that a threaded
implementation seems natural to you is a strong clue). The only real
difference here is that you originate the connections instead of accepting
them. Feel free to write me a private email and I can support you through
the Windows install problem you're having (you need a compiler to install
EventMachine). I can also write you a sample app based on my understanding
of what you're trying to do. If it works and you like it, we can post it
back to this list for the benefit of others.

···

On 7/4/06, Marcus Andersson <m-lists@bristav.se> wrote:

Francis Cianfrocca skrev:
> Look at EventMachine in Rubyforge.
>
On Windows XP:

C:\Downloads>gem install eventmachine-0.5.3-mswin32.gem
Attempting local installation of 'eventmachine-0.5.3-mswin32.gem'
ERROR: Error installing gem eventmachine-0.5.3-mswin32.gem[.gem]:
buffer error

I looked in the readme. There is an example there on how to create a
server. How would I use EventMachine to work as a client app?

Regards,

/Marcus

Francis-

  I am interested in EventMachine as well so I would love to follow your process of building something simple like this with EventMachine. So I vote to keep it on the list or please cc me in the process.

Thanks
-Ezra

···

On Jul 4, 2006, at 1:27 PM, Francis Cianfrocca wrote:

Your application sounds in many ways like a "server" in the sense that it
needs to maintain a lot of open connections (the fact that a threaded
implementation seems natural to you is a strong clue). The only real
difference here is that you originate the connections instead of accepting
them. Feel free to write me a private email and I can support you through
the Windows install problem you're having (you need a compiler to install
EventMachine). I can also write you a sample app based on my understanding
of what you're trying to do. If it works and you like it, we can post it
back to this list for the benefit of others.

Ezra: I sent Marcus the following description of an approach to his
application, and will post more to this list if the approach turns out to be
worth something.

(snipped from a private email:)
Ok, here's what I would do:
I assume you have a global hash that maps the description of each "customer"
with a status indicating whether or not it currently has an active client.
(You can use the same data structure to store and report status results
received from the connections.)
Have the EventMachine fire a timer every five seconds that examines each of
the customers and starts up a new client connection for every one that is
inactive. Once a connection is open for each customer, your
connection-handling code can start up a new connection whenever they close
(which is an event passed by EM to your code). The five-second timer is only
there for a heartbeat, to bootstrap the system, and in case an unexpected
exception occurs. Because there are no threads, there are no race
conditions. Very simple.

Quoting Ezra Zygmuntowicz <ezmobius@gmail.com>:

Your application sounds in many ways like a "server" in the sense that it
needs to maintain a lot of open connections (the fact that a threaded
implementation seems natural to you is a strong clue). The only real
difference here is that you originate the connections instead of accepting
them. Feel free to write me a private email and I can support you through
the Windows install problem you're having (you need a compiler to install
EventMachine). I can also write you a sample app based on my understanding
of what you're trying to do. If it works and you like it, we can post it
back to this list for the benefit of others.

Francis-

  I am interested in EventMachine as well so I would love to follow your
process of building something simple like this with EventMachine. So I
vote to keep it on the list or please cc me in the process.

Thanks
-Ezra

Me too, please.

···

On Jul 4, 2006, at 1:27 PM, Francis Cianfrocca wrote: