Multiple Class Instances Of EventMachine Rails - ruby-on-rails

I am trying to bind to two diferenet SMSCs through SMPP 3.4 from a single rails application using the ruby-smpp gem.
Following the example included on the documentation of this gem I have two configuration blocks pointing to the different ISPs i.e.
config_1 = {
#.......
}
config_2 = {
#.......
}
I go on to declare and run two instaces of the gateways as shown below:
gw_1 = SampleGateway.new
gw_1.start(config_1)
gw_2 = SampleGateway.new
gw_2.start(config_2)
I am able to bind to the respective ISPs but the problems I am experiancing are as follows:
Whenever one of the binds is lost (i.e. on unbound), both ISP connections are lost.
When I initiate/send an SMS to a particular ISP at least 2 times the number of SMSes will be sent throught that ISP (i.e. if i send 1 SMS throught ISP1, 2 SMSes will be delivered on the handset)
Any ideas as to how I can prevent the above from happening, or should I connect to the ISPs with two different rails apps?

The samplegateway provided by the project is not suitable for your usecase. if you check https://github.com/raykrueger/ruby-smpp/blob/master/examples/sample_gateway.rb#L64 the EventMachine connection is stored in a class variable, which means your second call gw_2.start(config_2) will just overwrite the first one.
You should probably orient yourself on the https://github.com/raykrueger/ruby-smpp basic usage and write your own Gateway

Related

Rails 6 with multiple database, auto change connection based on read or create query

The question might be silly and it's not practiced in real world. Anyway kindly give your thoughts/pros/cons....
Lets say I am having two database read replica database and master database
Scenario 1:
Model.all # It should query from read replica database
Scenario 2:
Model.create(attributes) # It should create data in master database
Scenario 3:
Model.where(condition: :some_condition).update(attributes) # It should read data from replica database and update the data in master database
Note: In runtime database should detect the query and process the above 3 scenario.
Questions:
Is this a valid expectation?
if Yes, How to achieve this case completely or partially?
if No, What wrong in this case and what issues we will be facing?
Rails 6 provides a framework for auto-routing incoming requests to either the primary database connection, or a read replica.
By default, this new functionality allows your app to automatically route read requests (GET, HEAD) to a read-relica database if it has been at least 2 seconds since the last write request (any request that is not a GET or HEAD request) was made.
The logic that specifies when a read request should be routed to a replica is specified in a resolver class, ActiveRecord::Middleware::DatabaseSelector::Resolver by default, which you would override if you wanted custom behavior.
The middleware also provides a session class, ActiveRecord::Middleware::DatabaseSelector::Resolver::Session that is tasked with keeping track of when the last write request was made. Like the resolver, this class can also be overridden.
To enable the default behavior, you would add the following configuration options to one of your app's environment files - config/environments/production.rb for example:
config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver =
ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_operations =
ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
If you decide to override the default functionality, you can use these configuration options to specify the delay you'd like to use, the name of your custom resolver class, and the name of your custom session class, both of which should be descendants of the default classes

Put class instance to class constant in initializers

In one of my old apps, I'm using several API connectors - like AWS or Mandill as example.
For some reason (may be I saw it somewhere, don't remember), I using class constant to initialize this objects on init stage of application.
As example:
/initializers/mandrill.rb:
require 'mandrill'
MANDRILL = Mandrill::API.new ENV['MANDRILL_APIKEY']
Now I can access MANDRILL class constant of my application in any method and use it. (full path MyApplication::Application::MANDRILL, or just MANDRILL). All working fine, example:
def update_mandrill
result = MANDRILL.inbound.update_route id, pattern, url
end
The question is: it is good practice to use such class constants? Or better create new class instance in every method that using this instance, like in example:
def update_mandrill
require 'mandrill'
mandrill = Mandrill::API.new ENV['MANDRILL_APIKEY']
result = mandrill.inbound.update_route id, pattern, url
end
Interesting question.
It's very handy approach but it may have cons in some scenarios.
Imagine you have a constant that either takes a lot of time to initialize or it loads a lot of data into memory. When its initialization takes long you essentially degrade app boot time (which may or may not be a problem, usually it will in development).
If it loads a lot of data into memory it may turn out it's gonna be a problem when running rake tasks for example which load entire environment. You may hit memory boundaries in use cases in which you essentially do not need this data at all.
I know one application which load a lot of data during boot - and it's done very deliberately. Sure, use case is a bit uncommon, but still.
Another thing to consider is - imagine, you're trying to establish connection to external service like Mongo or anything else. If this service is unavailable (what happens) your application won't be able to boot. Maybe this service is essential for app to work, and without it it would be "useless" anyway, but it's also possible that you essentially stop everything because storage in which you keeps log does not work.
I'm not saying you shouldn't use it as you suggested - I do it also in my apps, but you should be aware of potential drawbacks.
Yes, pre-creating a pseudo-constant object (like that api client) is usually a good idea. However, there is, approximately, a thousand ways go about it and the constant is not on top of my personal list.
These days I usually go with setting it in the env files.
# config/environments/production.rb
config.email_client = Mandrill::API.new ENV['MANDRILL_APIKEY'] # the real thing
# config/environments/test.rb
config.email_client = a_null_object # something that conforms to the same api, but does absolutely nothing
# config/environments/development.rb
config.email_client = a_dev_object # post to local smtp, or something
Then you refer to the client like this:
Rails.application.configuration.email_client
And the correct behaviour will be picked up in each env.
If I don't need this per-env variation, then I either use some kind of singleton object (EmailClient.get) or a global variable in the initializer ($email_client). It can be argued that a constant is better than global variable, semantically and because it raises a warning when you try to re-assign it. But I like that global variable stands out more. You see right away that it's something special. (And then again, it's only #3 in the list, so I don't do it very often.).

Rspec - combine expect_any_instance_of and a receive counts

I need to verify that any instance of my class receives a certain method, but I don't care if many instances receive it (they're supposed to).
I tried like this:
expect_any_instance_of(MyClass).to receive(:my_method).at_least(:once)
But apparently, it only allows for a single instance to receive the method multiple times, but not for different instances.
Is there a way to achieve that?
If you need to live with the code smell, this rspec-mocks Github issue suggests a solution along these lines:
receive_count = 0
allow_any_instance_of(MyClass).to receive(:my_method) { receive_count += 1 }
# Code to test here.
expect(receive_count).to be > 0
This is a known issue in rspec-mocks. From the v3.4 documentation on Any instance:
The rspec-mocks API is designed for individual object instances, but this feature operates on entire classes of objects. As a result there are some semantically confusing edge cases. For example, in expect_any_instance_of(Widget).to receive(:name).twice it isn't clear whether a specific instance is expected to receive name twice, or if two receives total are expected. (It's the former.)
Furthermore
Using this feature is often a design smell. It may be that your test is trying to do too much or that the object under test is too complex.
Do you have any way to refactor your test or app code to avoid the "confusing edge case"? Perhaps by constructing a test double and expecting it to receive messages?

JIRA 4.2.1 & JIRA 4.3.3 integration through email

I want to integrate 2 JIRA instances through email, one uses Jira 4.2.1 and the other uses 4.3.3.
one instance has certain custom fields, another has certain custom fields, both of the JIRA instances has to interchange the issue details, updates of the issue, through email. i.e both has to be in sync.
For Example
1) if an issue is created in Instance 1, a mail will be triggered and using that email, Instance 2 will create an issue there.
2) Also, if there is a update for an issue in Insance1 then a mail will be triggered to Instance 2 which will update the same issue in Instance 2.
Hope it clears !!
If I got your intentions right, i believe that there is an easier way to do so using the Jira remote API. For example, you could easily write a Python script, using the XML-RPC library, comparing the two systems and updating them if needed.
The problem with the email method you suggested is that you could easily create an endless loop of issue creating...
First, create a custom field in both instances, and call it something like "Sync". This will be used to mark issues once we'll sync them.
Next, enable the RPC plugin.
Finally, write a script that will copy the issues via RPC, example:
#!/usr/bin/python
# Sample Python client accessing JIRA via XML-RPC. Methods requiring
# more than basic user-level access are commented out.
#
# Refer to the XML-RPC Javadoc to see what calls are available:
# http://docs.atlassian.com/software/jira/docs/api/rpc-jira-plugin/latest/com/atlassian/jira/rpc/xmlrpc/XmlRpcService.html
import xmlrpclib
s1 = xmlrpclib.ServerProxy('http://your.first.jira.url/rpc/xmlrpc')
auth1 = s1.jira1.login('user', 'password')
s2 = xmlrpclib.ServerProxy('http://your.second.jira.url/rpc/xmlrpc')
auth2 = s2.jira1.login('user', 'password')
# go trough all issues that appear in the next filter
filter = "10200"
issues = s1.jira1.getIssuesFromFilter(auth1, filter)
for issue in issues:
# read issues:
for customFields in issue['customFieldValues']:
if customFields['customfieldId'] == 'customfield_10412': # sync custome field
# cf exists , dont sync!
continue
# no sync field, sync now
proj = issue['project']
type = issue['type']
sum = issue['summary']
desc = issue['project']
newissue = s2.jira1.createIssue(auth2, { "project": issue['project'], "type": issue['type'], "summary": issue['summary'], "description": issue['description']})
print "Created %s/browse/%s" % (s.jira1.getServerInfo(auth)['baseUrl'], newissue['key'])
# mark issue as synced
s.jira1.updateIssue(auth, issue['key'], {"customfield_10412": ["yes"]})
The script wasn't tested but should work. You'll probably need to copy the rest of the fields you have, check out this link for more info. As well, this is just one way sync, you have to sync it the other way around as well.

When should I create Solr connection in a Rails app

I'm accessing Solr in a Ruby on Rails application by using rsolr (not Sunspot). I create the local solr object that I use to send requests like this:
solr = RSolr.connect(:url => "http://localhost:8983/solr")
as far as I understand, this is not really a connection but just an object that will issue requests on demand, so it shouldn't be expensive to keep it initialized and it should never disconnect. According to that, it should be ok to have one global solr object, create it at start time and forget about it. Right? But maybe it's not thread safe?
When should I create the solr connection?
All that the RSolr.connect method really does is sanitize and save the options that you're using. You can see that method here. It's passed a new connection object (which, notably, doesn't have an initialize method, so it's not doing anything when created) and the options that you pass to RSolr.connect.
So yes, you're right -- no harm at all in connecting once and leaving it connected forever hanging around in a variable somewhere. (For example, I memoize the result of RSolr.connect in my Solr/Rails app.)

Resources