Ruby Concurrent Execution Queue
We want to build an execution queue that takes different commands from multiple clients (concurrently) and execute them one by one according to the command type. It needs to accept 3 types of commands:
The server has to print the result of each job in the server log.
Implement a multithreaded server that accepts multiple TCP connections. Clients can connect to the server and enqueue different kinds of jobs (defined in the server) that will run, according to the command used, in a synchronous or asynchronous way following a first come- first served criteria.
perform_now JobClass job_params
perform_later JobClass job_params
perform_in seconds_from_now JobClass job_params
ruby main.rb
to start the threads. This starts:localhost:2000
.telnet localhost 2000
.perform_now
, perform_later
or perform_in
commands and for the latter two see the result in the server terminal.Telnet console input/output:
Letis-MacBook-Pro:Server leti$ telnet localhost 2000
Trying ::1...
Connected to localhost.
Escape character is '^]'.
Hey there! Welcome :)
perform_now InvalidJob
That job class is not defined!
perform_now HelloWorldJob invalid_param
The job arguments are not correct :(
perform_now HelloWorldJob
Hello World
invalid_command
Sorry, that is not a valid command.
perform_now HelloMeJob
The job arguments are not correct :(
perform_now HelloMeJob leti esperon
Hello World leti esperon
perform_later InvalidJob
621dbfe9c0
perform_later HelloWorldJob
1fb6fe7b57
perform_later HelloMeJob leti esperon
f752c52fcc
perform_in 10 HelloWorldJob
25ed531e17
perform_in 2 HelloMeJob leti esperon
66672da45f
perform_in 1 InvalidJob
632b106483
perform_in 1 HelloMeJob missing_param
a70283beb7
Server output:
Connected a client.
Error executing ENQUEUED job InvalidJob - Result: That job class is not defined!
Finished computing ENQUEUED job HelloWorldJob - Result: Hello World
Finished computing ENQUEUED job HelloMeJob - Result: Hello World leti esperon
Finished computing SCHEDULED job HelloMeJob - Result: Hello World leti esperon
Finished computing SCHEDULED job HelloWorldJob - Result: Hello World
Error executing SCHEDULED job InvalidJob - Result: That job class is not defined!
Error executing SCHEDULED job HelloMeJob - Result: The job arguments are not correct :(
Clients listener:
Actively listens at and open tcp server to find connections and start a new client server thread for each new client connection.
Client server:
Takes care of a single client’s requests through an open connection. Reads their inputs and responds. Might enqueue jobs if the client asked for.
Worker server:
When started launches a certain number of worker threads that do polling over the jobs queue to execute the jobs that get enqueued in it.
Scheduled worker server:
Same than worker server but for jobs that need to run at a specific time.
Job:
Represents a task that needs to be ran. Has an autogenerated id, a class name and params. In the future it could also have retries count, date executed, etc.
Scheduled job:
Wrapper for Job
that adds a time from which it can be executed.
Queue adapter:
Encapsulates all the enqueueing/dequeueing of the jobs so the other classes are transparent to the implementation of the queues.
perform_now
command, the job is not stored anywhere but performed right away in the same client server thread.socket.accept
is a blocking method.print
with \n
was used instead of puts
since it is thread safe.Queue
class is already thread safe. There are thread safe implementations of arrays on concurrent-ruby
gem but I was not allowed to use it.QueueAdapter
class so changing the queue implementation should not impact on any other part of the code, not even on the specs of this class.perform_in
and perform_later
actions it is validated that the first param is a valid number and that the job class name is present, but not if the class exists and if the arguments inputted are the correct number.print
.Specs output:
Open a terminal in the project root folder and run tests with rspec
command.
Letis-MacBook-Pro:Server leti$ rspec
.............................................................................
Finished in 0.07414 seconds (files took 0.31294 seconds to load)
76 examples, 0 failures