Я использую Grails для отправки большого количества электронных писем в формате HTML. Я использую SimpleTemplateEngine для создания тел сообщений электронной почты следующим образом:
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
Вот шаблон, который я пытаюсь визуализировать для каждого тела письма:
<!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> <br>
More text
<br> <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>
Как только эти методы вернут карту ccIdToEmail, я отправлю все свои электронные письма. По какой-то причине подготовка этой карты clientContactIds и тел электронной почты приводит к зависанию моего приложения на любой из двух строк, перечисленных выше. Я могу успешно подготовить / отправить ~ 140 писем, прежде чем он зависнет. Это происходит очень стабильно.
Кто-нибудь знает, почему это сработает, но перестанет работать после создания ~ 140 тел электронной почты из шаблона? Я не смог найти в Интернете ничего о других людях, у которых возникли проблемы с этим.
Андрей





Похоже на проблему с синхронизацией. В качестве первого шага вы должны создать шаблон вне цикла. Так как нет необходимости каждый раз заново создавать шаблон.
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
Если это не поможет, может помочь, если вы разместите содержимое шаблона и / или источник ClientContact.
hth, Сиги
Похоже, что возникла проблема с отложенной загрузкой моих владельцев контактов с клиентами в шаблон. Вместо того, чтобы ожидать загрузки владельцев (неэффективно), в то время как SimpleTemplateEngine создает тело письма, я с нетерпением вызываю владельцев перед привязкой / созданием тела.
Мой приведенный выше код теперь выглядит так:
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
По-прежнему неэффективно делать такое количество запросов для каждого из контактов клиента, но ЭТО РАБОТАЕТ. Я не могу объяснить, почему ленивая загрузка их во время создания шаблона привела к зависанию grails / groovy, но это было так. Если кто-нибудь может это объяснить, я был бы признателен.
Спасибо за ваши ответы. Зигфрид ... ты направил меня в правильном направлении.
Андрей
Я изменил свой код на тот, что есть у вас, но он по-прежнему вызывает зависание на 141. Я попытался просто создать все тела электронной почты, но не отправлять, и он работает с 160+. В отправке этих писем есть что-то, что вызывает проблемы. Однако, судя по моим выводам println, перед отправкой он зависает.