RabbitMQ 出队发送邮件注意事项
Contents
线上一个发送邮件的系统,通过 RabbitMQ 出队发送系统中的邮件时,发现虽然 consumer 连接在那里,但是日志中却没有任何输出相关的成功或失败或抛出异常的信息。
这种情况下,我的解决思路如下
打印出当前 JVM 线程栈
线程栈如下,然后直接定位到相应的代码所在的线程:
"org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer#6-1" prio=10 tid=0x00007f296c5c6000 nid=0x5362 runnable [0x00007f29963e2000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:312)
at sun.security.ssl.InputRecord.read(InputRecord.java:350)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927)
- locked <0x0000000787590178> (a java.lang.Object)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:884)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
- locked <0x0000000787590200> (a sun.security.ssl.AppInputStream)
at com.sun.mail.util.TraceInputStream.read(TraceInputStream.java:110)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
- locked <0x0000000787591850> (a java.io.BufferedInputStream)
at com.sun.mail.util.LineInputStream.readLine(LineInputStream.java:89)
at com.sun.mail.smtp.SMTPTransport.readServerResponse(SMTPTransport.java:2131)
at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2036)
at com.sun.mail.smtp.SMTPTransport.data(SMTPTransport.java:1849)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1099)
- locked <0x0000000787590a78> (a com.sun.mail.smtp.SMTPTransport)
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:448)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:345)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:340)
at com.company.util.SendMail.sendFileMail(SendMail.java:110)
at com.company.listener.MailListener.sendMail(MailListener.java:29)
at sun.reflect.GeneratedMethodAccessor433.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:269)
at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:387)
at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:298)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:777)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:700)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:95)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:187)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1187)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:681)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1165)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1149)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1100(SimpleMessageListenerContainer.java:95)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1312)
at java.lang.Thread.run(Thread.java:722)
Locked ownable synchronizers:
- None
可以看到,问题代码所在的位置是:
at com.company.util.SendMail.sendFileMail(SendMail.java:110)
at com.company.listener.MailListener.sendMail(MailListener.java:29)
之后的栈中,出现了这么多locked
线程。最后停留在了读取数据相关的方法里。这样子就可以表明,它在无限等待读取数据了。
项目里的 sender 的属性配置
mail.host=smtp.exmail.qq.com
## service (finding password, active accout)
mail.service.username=company
mail.service.password=password
## Mail connection properties
mail.smtp.host=smtp.exmail.qq.com
mail.mime.charset=UTF-8
mail.smtp.starttls.enable=true
mail.smtp.socketFactory.fallback=false
mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
mail.smtp.port=465
mail.smtp.socketFactory.port=465
mail.smtp.auth=true
mail.transport.protocol=smtp
配置属性的问题
这个是因为没有设置相关的 timeout 属性,导致一直在等待,最后线程不可用了。
javaMailProperties 所有属性
解决
## 连接超时
mail.smtp.connectiontimeout
## 读取数据超时
mail.smtp.timeout
## 写入数据超时
mail.smtp.writetimeout
加上这三个属性,设置适合的超时时间。超时后,重新进队再继续重试即可。