Hi James,

Thank you for the thorough explanation! So if I understand you correctly,
if no calls are made to the executor thread, it will just rest silently
until queue-email is called again - not consuming any server resources. Are
there any recommendations for the number of worker threads when each does
IO?

Thanks,
Brjánn

On Thu, 25 Oct 2018 at 19:45, James Reeves <ja...@booleanknot.com> wrote:

> The Java executor classes are essentially a queue backed by a thread pool
> of workers.
>
> So suppose we create a new executor:
>
> (def executor
>   (java.util.concurrent.Executors/newFixedThreadPool 32))
>
> This creates an ExecutorService object with a pool of 32 worker threads.
> We can pass it a zero-argument function to execute:
>
> (.execute executor (fn [] (prn "Hello World")))
>
> This function is placed on a queue until one of the 32 worker threads is
> available to process it. In this case the function prints a message, but
> you could write something to send an email instead:
>
> (defn queue-email [email]
>   (.execute executor (fn [] (send-email email)))
>
> If we execute "queue-email" 10,000 times, then 10,000 "send-email" jobs
> will be passed to the executor. The executor will pass them onto its 32
> workers, effectively processing 32 at a time until it exhausts the queue.
>
> If you want fewer emails to be sent at once, you can reduce the worker
> thread pool size. In my earlier example, I used an executor with only one
> worker thread.
>
> On Thu, 25 Oct 2018 at 18:17, <brj...@gmail.com> wrote:
>
>> Hi James,
>>
>> Thanks! How would one create a thread that continuously monitors a mail
>> queue and sends any mails in it? Or do you mean that I would create one
>> thread per mail that I want to send? Wouldn't that create a problem if I'm
>> about to send 10000 mails in one go?
>>
>> And thanks for the heads up regarding indefinite blocking - I'll make
>> sure to guard against that.
>>
>> Thanks,
>> Brjánn
>>
>> On Thu, 25 Oct 2018 at 18:57, James Reeves <ja...@booleanknot.com> wrote:
>>
>>> Hi Brjánn,
>>>
>>> Executing queued jobs in a background thread is a common task, and as it
>>> happens there's a set of Java classes to do just that.
>>>
>>> (let [e (java.util.concurrent.Executors/newSingleThreadExecutor)]
>>>   (.execute e #(prn "foo"))
>>>   (.execute e #(prn "bar"))
>>>   (Thread/sleep 1000)
>>>   (.execute e #(prn "baz")))
>>>
>>> Don't worry about cleaning up a single thread. An inactive thread takes
>>> up a minimal amount of VM memory and no CPU. You're going to use up more OS
>>> resources deleting and recreating the thread.
>>>
>>> You do need to be careful that sending an email doesn't block
>>> indefinitely, but usually I/O operations come with timeouts. Just ensure
>>> you set a reasonable timeout and do something sensible when you can't send.
>>>
>>> On Thu, 25 Oct 2018 at 16:46, <brj...@gmail.com> wrote:
>>>
>>>> Hi,
>>>>
>>>> First, I would like to briefly present myself to the list. I'm a
>>>> psychologist and researcher at the Karolinska Institutet in Stockholm,
>>>> Sweden. I do research within the field of internet-based psychological
>>>> treatment - which is a field that has grown a lot during the last 10-15
>>>> years. I have developed my own web platform to deliver these treatments to
>>>> patients with different mental and medical conditions. I wrote the first
>>>> version in PHP, and not being a professional programmer, the code base is a
>>>> big mess after > 10 years of development.
>>>>
>>>> Two years ago, a friend introduced me to Clojure. I had never worked
>>>> with a lisp before, but I quickly fell completely in love with it. So many
>>>> of the issues of programming in PHP completely disappeared! Words cannot
>>>> express my gratitude to Rich for inventing Clojure, the core team, all
>>>> developers out there who write extremely useful libraries, and my friend
>>>> for introducing Clojure to me.
>>>>
>>>> I decided to completely rewrite my web platform in Clojure. I've chosen
>>>> to do a gradual move from PHP to Clojure, meaning that I replace PHP code
>>>> with Clojure code component by component and continuously test in
>>>> production. Like I said, I'm not a professional programmer, and this
>>>> venture poses a lot of challenges. I try to read everything I find in books
>>>> and on the web, but when it comes to more complex issues, such as threads
>>>> and async programming, I feel that I end up almost guessing and with a lot
>>>> of trial and error. I have no idea how cautious one should be when
>>>> launching a new thread (while it completely occupy the server???) and am
>>>> often surprised when my go blocks suddenly freeze. I feel that I am at the
>>>> mercy of the Clojure community if I want to understand these (and many
>>>> other!) issues.
>>>>
>>>> This leads me to the subject of this email. I've decided to migrate my
>>>> mail queue from PHP to Clojure. In PHP, it's just a cron job that executes
>>>> every five minutes to send all emails (and actually also SMS-messages, but
>>>> not really relevant) that have been queued.
>>>>
>>>> I've written a basic mock Clojure implementation with the following
>>>> goals
>>>> - All messages should be sent async, i..e, the web user should not have
>>>> to wait while the email is being sent. -> I'm sending them in a separate
>>>> thread.
>>>> - I have a fear that if I have a thread dedicated only to sending
>>>> emails, I'm wasting server resources. -> I want the thread to die 5 seconds
>>>> after the last email in the queue has been sent.
>>>>
>>>> My implementation basically consists of
>>>> - An eternal go loop that receives a notification through a channel if
>>>> new messages have been queued
>>>> - The go loop checks if the mail sender thread is running. If not, it
>>>> starts it.
>>>> - The mail sender thread dies 5 secs after the last email was sent
>>>> - The state of the thread (running / not running) is stored in an agent
>>>> to avoid race conditions (i.e., starting multiple threads or not starting a
>>>> thread because it is running when its status is checked but stops right
>>>> after).
>>>>
>>>> My code is here
>>>> https://gist.github.com/brjann/2aef16849b9bd445374cb6b31efece60
>>>>
>>>> If any of you have had the time and energy to read this far (including
>>>> the code), I would be very grateful for your input.
>>>> - Is there a risk that my go block will hang?
>>>> - Have I eliminated the risk for race conditions?
>>>> - Do I really need to kill the thread or is there no risk for thread
>>>> starvation on the server (I will probably
>>>> - Could I use send instead of send-off? I guess that I am now using two
>>>> threads, one for the sender and one each time I send a message using
>>>> send-off.
>>>> - Any newbie mistakes / coding style issues?
>>>> - Could this be done in a better/simpler way???
>>>>
>>>> (Btw, I would be very grateful for feedback on the form of my question
>>>> if you have any. Are there better/other forums? Could I present the
>>>> question or code in a another manner to help you understand better?)
>>>>
>>>> I am happy for any replies - on the list or backchannel. And I hope
>>>> that you feel that I have not misused your inbox (I may repeat this
>>>> behavior...).
>>>>
>>>> Thanks,
>>>> Brjánn
>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google
>>>> Groups "Clojure" group.
>>>> To post to this group, send email to clojure@googlegroups.com
>>>> Note that posts from new members are moderated - please be patient with
>>>> your first post.
>>>> To unsubscribe from this group, send email to
>>>> clojure+unsubscr...@googlegroups.com
>>>> For more options, visit this group at
>>>> http://groups.google.com/group/clojure?hl=en
>>>> ---
>>>> You received this message because you are subscribed to the Google
>>>> Groups "Clojure" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>> an email to clojure+unsubscr...@googlegroups.com.
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>>
>>> --
>>> James Reeves
>>> booleanknot.com
>>>
>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups "Clojure" group.
>>> To post to this group, send email to clojure@googlegroups.com
>>> Note that posts from new members are moderated - please be patient with
>>> your first post.
>>> To unsubscribe from this group, send email to
>>> clojure+unsubscr...@googlegroups.com
>>> For more options, visit this group at
>>> http://groups.google.com/group/clojure?hl=en
>>> ---
>>> You received this message because you are subscribed to the Google
>>> Groups "Clojure" group.
>>> To unsubscribe from this group and stop receiving emails from it, send
>>> an email to clojure+unsubscr...@googlegroups.com.
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clojure@googlegroups.com
>> Note that posts from new members are moderated - please be patient with
>> your first post.
>> To unsubscribe from this group, send email to
>> clojure+unsubscr...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "Clojure" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to clojure+unsubscr...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>
> --
> James Reeves
> booleanknot.com
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to