线上一个发送邮件的系统,通过 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

加上这三个属性,设置适合的超时时间。超时后,重新进队再继续重试即可。