1
votes

I'm using Grails to send a large number of HTML emails. I use the SimpleTemplateEngine to create my email bodies in this fashion:

def ccIdToEmailMap = [:]
def emailTemplateFile = Utilities.retrieveFile("email${File.separator}emailTemplate.gtpl")
def engine = new SimpleTemplateEngine()
def clientContacts = ClientContact.list()
for(ClientContact cc in clientContactList) {
   def binding = [clientContact : cc]

   //STOPS (FREEZES) EITHER HERE OR....
   def template = template = engine.createTemplate(emailTemplateFile).make(binding)

   //OR STOPS (FREEZES) HERE
   def body = template.toString()

   def email = [text: body, to: cc.emailAddress]
   ccIdToEmailMap.put(cc.id, email)
   println "added to map"
}
return ccIdToEmailMap

Here is the template I'm trying to render for each email body:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">


<html>
<head>
<title>Happy Holidays from google Partners</title>
</head>

<body>
    <table width="492" cellpadding="0" cellspacing="0" style="border:2px solid #acacac;margin:8px auto;" align="center">
        <tr>
            <td colspan="5" bgcolor="#c1e0f3"><img src="http://www.google.com/holiday2008/cardbg.gif" width="492" height="10" border="0"></td>
        </tr>

        <tr>
            <td width="6" bgcolor="#c1e0f3"><img src="http://www.google.com/holiday2008/sidebgl.gif" width="6" height="453" border="0"></td>
            <td style="background:#fff;border:1px solid #acacac;padding:2px;" width="228">
                <div style="width:208px;margin:4px 8px 0px 8px; color:#515151;">
                <font face="Times New Roman" size="2">
                <span style="font:14px 'Times New Roman',times,serif;">Static text that is the same for each email
                <br>&nbsp;<br>
                More text
                <br>&nbsp;<br>
                We wish you health and happiness during the holidays and a year of growth in 2009.
                </span>
                </font>
                </div>
            </td>
            <td style="background:#c9f4fe;border-top:1px solid #acacac;border-bottom:1px solid #acacac;" width="5"><img src="http://www.google.com/holiday2008/vertbg.gif" border="0" height="453" width="5"></td>
            <td width="247" style="background:#fff;border:1px solid #acacac;"><img src="http://www.google.com/holiday2008/snowing.gif" width="247" height="453" border="0"></td>
            <td width="6" bgcolor="#c1e0f3"><img src="http://www.google.com/holiday2008/sidebgr.gif" width="6" height="453" border="0"></td>
        </tr>
        <tr>
            <td width="6" bgcolor="#c1e0f3"><img src="http://www.google.com/holiday2008/sidebgr.gif" width="6" height="38" border="0"></td>
            <td colspan="3" style="border:1px solid #acacac;" align="center"><img src="http://www.google.com/holiday2008/happyholidays.gif" width="480" height="38" alt="Happy Holidays" border="0"></td>
            <td width="6" bgcolor="#c1e0f3"><img src="http://www.google.com/holiday2008/sidebgr.gif" width="6" height="38" border="0"></td>
        </tr>
        <tr>
            <td width="6" bgcolor="#c1e0f3"><img src="http://www.google.com/holiday2008/sidebgr.gif" width="6" height="120" border="0"></td>
            <td colspan="3" style="background-color#fff;border:1px solid #acacac;padding:2px;" valign="top">
                <img src="http://www.google.com/holiday2008/gogl_logo_card.gif" width="140" height="40" alt="google partners" border="0" align="right" hspace="4" vspace="4" />
                <font face="Times New Roman" size="2">
                <div style="padding:4px;font:12pt 'Times New Roman',serif;color:#515151;">
                <span style="font-size:10pt"><i>from:</i></span>

                    <div style="padding:2px 4px;">
                        <% clientContact.owners.eachWithIndex { it, i -> %>
                            <% if(i < (clientContact.owners.size() - 1)) { %>
                                ${it.toString()},
                            <% }else { %>
                                ${it.toString()}
                            <% } %>
                        <% } %>
                    </div>
                </div>
                </font>
            </td>
            <td width="6" bgcolor="#c1e0f3"><img src="http://www.google.com/holiday2008/sidebgr.gif" width="6" height="120" border="0"></td>
        </tr>
        <tr>
            <td colspan="5" bgcolor="#c1e0f3"><img src="http://www.google.com/holiday2008/cardbg.gif" width="492" height="10" border="0"></td>

        </tr>
    </table>
</body>
</html>

Once this methods returns the ccIdToEmail map, I send out all of my emails. For some reason, preparing this map of clientContactIds and email bodies causes my application to freeze at either of the two lines listed above. I can successfully prepare/send ~140 emails before it freezes. This happens very consistently.

Does anyone know why this would work but then stop working after a ~140 email bodies are created from a template? I haven't been able to find anything online about other peope having trouble with this.

Andrew

2

2 Answers

1
votes

Sounds like a synchronization issue. As a first step, you should create the template outside of the loop. Since there is no need to recreate the template every time.

    def ccIdToEmailMap = [:]
    def emailTemplateFile = Utilities.retrieveFile("email${File.separator}emailTemplate.gtpl")
    def engine = new SimpleTemplateEngine()
    def template = engine.createTemplate(emailTemplateFile)
    def clientContacts = ClientContact.list()
    for(ClientContact cc in clientContactList)
    {
            def binding = [clientContact : cc]
            def body = template.make(binding).toString()
            def email = [text: body, to: cc.emailAddress]
            ccIdToEmailMap.put(cc.id, email)
            println "added to map"
    }
    return ccIdToEmailMap

If it doesn't help, it might help if you'd post the template content and/or the source of ClientContact.

hth, Sigi

0
votes

It appears that there was an issue with lazy loading my client contact owners in the template. Instead of expecting the owners to be loaded (inefficiently), while SimpleTemplateEngine is making the email body, I eagerly fetch the owners before binding/making the body.

My above code now looks like this:

    def emailTemplateFile = null
    def ccIdToEmailMap = [:]

    emailTemplateFile = Utilities.retrieveFile("email${File.separator}emailTemplate.gtpl")
    def engine = new SimpleTemplateEngine()
    def template = engine.createTemplate(emailTemplateFile)
    for(ClientContact cc in clientContactList)
    {
        //there was a locking problem when we tried to create the template for too many client contacts
        //i believe it was caused by lazy-fetching of the person/owners.  So, I fetch them before we bind
        //and make the email body.
        def criteria = ClientContact.createCriteria()
        cc = criteria.get {
            eq("id", cc.id)
            fetchMode('relationship', FM.EAGER)
            fetchMode('relationship.person', FM.EAGER)
        }
        def binding = [clientContact : cc]
        def body = template.make(binding).toString()
        def email = [text: body, to: cc.emailAddress]
        ccIdToEmailMap.put(cc.id, email)
    }

    return ccIdToEmailMap

It's still kind of inefficient to make that many queries for each of the client-contacts, but IT WORKS. I can't explain why lazy loading them during template making caused grails/groovy to freeze, but it did. If anyone can explain that, I would appreciate it.

Thank you for your answers. Siegfried... you got me started in the right direction.

Andrew