I am sending mail to the users using actionmailer through postmark. This is my code in controller:
#users = User.where(some condition)
#product = Product.find_by_name(some name).first
for user in #users
UserMailer.new_product_arrival(user, #product, home_url).deliver
end
and this my user_mailer.rb
def new_product_arrival(user,product,home_url)
#from = Settings.mailer_from_address
#recipients = user.login
#sent_on = Time.now
#user = user
#product = product
#content_type = "text/html"
#home_url = home_url
end
The problem is that if there are more than 10 users it takes a very long time because of the for loop. I need to know if we can handle this by using multi-threading or background job. I don't want to use background job, but can anyone tell me how to implement the above using multi-threading.
I am using ruby 1.8.7 and rails 3.0.7
There basically two ways to wrap your loop in order to get "multi-threading":
Spwan a thread for each delivery and join them back to the main thread
threads = []
for user in #users
threads << Thread.new do
UserMailer.new_product_arrival(user, #product, home_url).deliver
end
end
threads.each(&:join)
fork over the entire rails app ( pretty messy but the rails app serving the request will respond immediately ) and have the process detached:
process = fork do
for user in #users
UserMailer.new_product_arrival(user, #product, home_url).deliver
end
Process.kill("HUP")
#sends the kill signal to current Process, which is the Rails App sending your emails
end
Process.detach(process)
Hope that helps
our developer Artem recently made a major update to the Postmark gem
which allows you to send emails easily in batches, which should allow you to send emails faster. Check it out.
Try delayed_job gem. This is a database-based background job gem. We used it in an e-commerce website, for example, sending order confirmation emails to users.
These tasks can happen asynchronously in the background, because your Rails app doesn't need
them executed immediately.
um im a rails student from nairobi dev school kenya ..and i think you can give this a try ,..soo what you are having there is the delayed response due to the number of users ..you can try long polling an example
poll = function (){
s.ajax{
url:/'chat.json'
data: { last_time: get last_time () }
}}.done(function(data) {
// handle data
setTimeout(poll,1000);
});
}
try that in your ow way ..this is useful for a real time application..o you can use even action controller:: live ..i think youre farmiliar with threading with rails .also .the above exmples will hep you ,,hopefuly
\
Related
I am very new to NodeJS and trying to develop an application which acts as a scheduler that tries to fetch data from ELK and sends the processed data to another ELK. I am able to achieve the expected behaviour but after completing all the processes, scheduler job does not exists and wait for another scheduler job to come up.
Note: This scheduler runs every 3 minutes.
job.js
const self = module.exports = {
async schedule() {
if (process.env.SCHEDULER == "MinuteFrequency") {
var timenow = moment().seconds(0).milliseconds(0).valueOf();
var endtime = timenow - 60000;
var starttime = endtime - 60000 * 3;
//sendData is an async method
reports.sendData(starttime, endtime, "SCHEDULER");
}
}
}
I tried various solutions such Promise.allSettled(....., Promise.resolve(true), etc, but not able to fix this.
As per my requirement, I want the scheduler to complete and process and exit so that I can save some resources as I am planning to deploy the application using Kubernetes cronjobs.
When all your work is done, you can call process.exit() to cause your application to exit.
In this particular code, you may need to know when reports.sendData() is actually done before exiting. We would have to know what that code is and/or see the code to know how to know when it is done. Just because it's an async function doesn't mean it's written properly to return a promise that resolves when it's done. If you want further help, show us the code for sendData() and any code that it calls too.
I have just started using locust with one custom client. At the end of the test (on_stop) I am fetching some results from APM and logging them.
Issue : when I use below command, all 1000 users are fetching those details and logging the data from APM. But I want only the 1st user to do this job and let other users to ignore this call.
$ locust -f --headless -u 1000 -r 100 --run-time 1h30m
Please let me know if someone has done something similar earlier. Thanks in advance.
I think what you probably want is test_stop EventHook. It runs once when the test is stopped. If you run in distributed mode, it runs once only on the master.
https://docs.locust.io/en/stable/api.html#locust.event.Events.test_stop
My understanding is that you are not running in distributed mode and you are using User class' on_stop method. I would try handling it with some global variable, it is quick and might need some work, like this:
apm_logging_user_assigned = False
class MyUser(User):
test stuff here ...
def on_start(self):
if apm_logging_user_assigned is False:
self.apm_log = True
apm_logging_user_assigned = True
super().on_start()
def on_stop(self):
if self.apm_log:
do your apm stuff here...
super().on_stop()
I am using angular 5 with pouchdb. When I save a user I need to show it immediately in the users list. Meanwhile a background thread must geolocate the users city and update its coordinates for that user.
The geolocation calculation takes a second or two to load that is why I am thinking of running in a background thread.
I looked into angular service worker, But I think its for getting files for offline.
I also looked angular cli web worker, But It did not mention how to call a background service and get a value back to main thread.
Is there a clear way to run a background thread in angular 5?
Using rxjs you can define and create an observable that do what you want :
myObservable = Observable.create(function (observer) {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => observer.next(position));
}
});
Then use it to get the desired value asynchronously :
myObservable.subscribe(pushedValue => console.log(pushedValue));
Here is a running example
This is not real multithread (not needed in this case in my opinion), for that you need to look more to web workers.
For Aangular 5 or under, I am using setTimout()
var _setTimeoutHandler = setTimout(() => { myfunction(){}})
Make sure you clear variable _setTimeoutHandler before quit to avoid resource leaking
I am also searching better way.
I have already written a request-method in java that sends a request to a simple Server. I have written this simple server and the Connection is based on sockets. When the server has the answer for the request, it will send it automatically to client. Now I want to write a new method that can behave as following:
if the server does not answer after a fixed period of time, then I send a new Request to the server using my request-method
My problem is to implement this idea. I am thinking in launching a thread, whenever the request-method is executed. If this thread does not hear something for fixed period of time, then the request method should be executed again. But how can I hear from the same socket used between that client and server?
I am also asking,if there is a simpler method that does not use threads
curently I am working on this idea
I am working on this idea:
1)send a request using my request-method
2)launch a thread for hearing from socket
3)If(no answer){ go to (1)}
else{
exit
}
I have some difficulties in step 3. How I can go to (1)
You may be able to accomplish this with a single thread using a SocketChannel and a Selector, see also these tutorials on SocketChannel and Selector. The gist of it is that you'll use long-polling on the Selector to let you know when your SocketChannel(s) are ready to read/write/etc using Selector#select(long timeout). (SocketChannel supports non-blocking, but from your problem description it sounds like things would be simpler using blocking)
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
Selector selector = Selector.open();
SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);
// returns the number of channels ready after 5000ms; if you have
// multiple channels attached to the selector then you may prefer
// to iterate through the SelectionKeys
if(selector.select(5000) > 0) {
SocketChannel keyedChannel = (SocketChannel)key.channel();
// read/write the SocketChannel
} else {
// I think your best bet here is to close and reopen the Socket
// or to reinstantiate a new socket - depends on your Request method
}
I am working on this idea:
1)send a request using my request-method
2)launch a thread for hearing from socket
3)If(no answer) then go to (1)
Is there a way to print multiple jobs in a row, without letting another user send a print job in between? (sort of "don't give the token to another user as long as my print jobs haven't finished")
It's a shared printer and many users have access to it, and what I'm printig is a big document so it takes some time;
I'm using more then one job because its pages are not to be printed from the same paper tray, so I have to switch the paper source in my code.
Help please! and thanks in advance.
P.S. I'm using the PrintDocument object of .Net
Instead of using multiple jobs, I can just change the settings for each page when printing (modify the PrintPageEventHandler), here's a link, and a sample of my code:
private void PrintPage(object sender, PrintPageEventArgs ev)
{
using (Metafile pageImage = new Metafile(streamList[currentPageIndex]))
{
// If it's the first page
if (currentPageIndex == 0)
{
// Use a certain tray
ev.PageSettings.PaperSource = PaperTrayPage1;
}
// For the rest of the document
else
{
// Use another tray
ev.PageSettings.PaperSource = PaperTrayRest;
}
currentPageIndex++;
ev.Graphics.DrawImage(pageImage, ev.PageBounds);
ev.HasMorePages = (currentPageIndex < streamList.Count);
}
}
Combining multiple jobs (PrintDocument objects) is possible, here's an example.
There isn't, as far are I know, you'd need to either keep the printer busy by keeping the job open and sending PJL or other commands that don't eject a page. The other option is to concatenate your jobs together into one large job. I guess you could also programatically pause the shared print queue and send the data directly using a direct IP print port or something. In the end there isn't an elegant solution to this.