[請益] 程式寄信方面的問題

作者: a47135 (金屬史萊姆)   2016-04-08 16:23:35
最近遇到一個問題,所以上來問問看有沒有人能解惑
我們的程式有時候會進行大量發信的動作
程式語言是C#,用微軟的Exchange.WebServices元件來做發信
發信伺服器是他們公司自己架的
我們寄信為了不影響使用者操作,所以寄信都是new一個Thread來做Send Mail的動作
問題來了
有寫Log紀錄信件對象和信件內容,所以可以確認發出SendMail要求的時候傳送的資料是
正確的(信件內容、對象、認證資料等)
當信件發送量過大的時候他們信件伺服器寄出的信件的內容和對象偶爾會錯亂的情況,像
是寄給A的信件內容卻是前一封發給B的信件內容
解決方式就是改成每5秒才做一次寄信動作(之前測2、3秒還是偶爾會有問題)
第一次遇到這種情況,雖然已經解決了,但是很好奇到底是他們家伺服器問題還是什麼原
因呢?
是否有人可以解惑一下
作者: LaPass (LaPass)   2016-04-08 16:28:00
看起來像是執行緒安全問題
作者: ken1325 (優質水瓶男)   2016-04-08 16:57:00
你們有做lock嗎
作者: LaPass (LaPass)   2016-04-08 17:06:00
send_Thread 的宣告跟變動請貼出來
作者: manaup   2016-04-08 17:07:00
程式寫成這樣 再加上這種說明 九成九是程式有BUG應該就是L大說的問題
作者: LaPass (LaPass)   2016-04-08 17:39:00
private [static] SmtpClient smtp; 問題可能在這裡你研究一下 synchronize 怎麼用,然後替smtp加上去或是乾脆把 static 拿掉,每次都重新建立一次smtp
作者: manaup   2016-04-08 17:45:00
L大是好人 (if u r good @ sth, dont do it for free.
作者: LaPass (LaPass)   2016-04-08 17:46:00
我只有點出問題而已,這個東西要講清楚的話可是要講上好幾頁,他自己去google會比等我打出來快。
作者: sing10407 (阿U)   2016-04-08 17:49:00
答案出來了,static會在memory保留同一個記憶體位置因此用thread時會一直去改到別人的值,不是獨立的物件
作者: LaPass (LaPass)   2016-04-08 17:53:00
其實最好還是先去看一下 SmtpClient 有沒有執行緒安全他的javadoc上應該會寫,如果沒有,那應該就是這邊了那就..... 應該是對方的mail server或是更底層的問題了
作者: a47135 (金屬史萊姆)   2016-04-08 18:08:00
的確上百家客戶就他們家會這樣XD
作者: sing10407 (阿U)   2016-04-08 18:08:00
建議先改改看
作者: a47135 (金屬史萊姆)   2016-04-08 18:16:00
恩,反正那個看起來有點多餘,而且改了也不影響結果還是謝謝各位的建議,至少以後程式記得會考慮這方面的問題XD執行緒安全畢業後就變成名詞了,比較少考慮到這塊XD多謝L大
作者: shadow0326 (非議)   2016-04-08 18:33:00
呃,static members是thread-safe那句話後面還有一句instance members不保證是thread-safe
作者: qrtt1 (有些事,有時候。。。)   2016-04-08 18:35:00
InitSMTP_MailMassage 為何不直接回傳 message_SMTP而卻是跟其他 method 共用這個變數!?
作者: shadow0326 (非議)   2016-04-08 18:36:00
你可能把那句話誤會成static SmtpClient instance是thread-safe的...那誤會可大了現在是講該類別自己的成員(也就是該物件自己的state)跟傳進的參數無關啊
作者: chrischen (一個人的長假)   2016-04-08 18:56:00
共用變數+race codition,問題在那堆底線開頭的變數
作者: x000032001 (版廢了該走了)   2016-04-08 19:13:00
重點是member..就是這class底下的變數 不是講他自身不是你把SmtpClient宣告public static 他就很安全了
作者: gn01838335 (寂靜的生存者)   2016-04-08 19:36:00
static 或 資源競爭 對於某事情A未處理完被B搶走資源 沒有singleton研判最後寄mail地方可能是關鍵,寫個log記錄所有寄信和內容從這方向查感覺比較能抓到問題
作者: alog (A肉哥)   2016-04-08 20:26:00
你們去買mailgun然後把smtp換成mailgun提供的伺服器 送送看你們所謂的大量郵件如果會出錯 是你們程式錯 如果沒有錯 就是對方的smtp server有問題看一下email source code有沒有email server版本*smtp 版本資訊然後在搜尋一下是不是他們smtp server是不是版本沒更新或看這軟體有沒有changelog有記載這類問題的
作者: chrischen (一個人的長假)   2016-04-09 09:02:00
沒貼完整code 用猜的看不準 丟到github公開review吧
作者: lovdkkkk (dk)   2016-04-09 10:38:00
這寫法它是 thread safe 也沒有用啊 0rz在 Init_SMTPClient 它會不斷地被換成新的實體要寫 log 直接開 smtp 本身的送信記錄 log 最準要測可以把間隔縮成 0 秒看別家會不會也出問題 XD
作者: evanslify (evs)   2016-04-09 17:48:00
直覺覺得, 你踩到雷; 如果間隔0會不會100%出錯?
作者: brucetu (sec)   2016-04-09 20:20:00
log應該留在最後面,現在這樣不是等於白留了嗎?還有為什麼不改成固定用一個thread發就好,要每一個寄信動作都用一個新的thread呢 徒增race condiction的可能性沒有信要送的時候就sleep,耗用的資源基本是0另外… 上個跟list傳值有關的解釋The澑eference湶s passThe澑eference湶s passed毪y value.Arrays in .NET are oThe reference is passed by valueArrays in .net are object on the heap, so you have a reference. That reference is passed by value, meaning that changes to the氲ontents漑f themeaning that changes to the contrnts of the array will be seen by the caller ,but reassigning the array wont.似乎代表著,你建構一個mail,傳cc的list 進去之後,呼叫send start一呼叫 mail.send ,start 一個new thread,接著讀取下一份資料,準備建構新的mail,這時如果外層沒有assign一個新的list給cc,而是把原本的ccList直接clear再add ,就會修改到前一個mail的_cc 因為都是指向同一個list,所以在mail建構的那邊應該對list做個clone比較安全,雖然你不一定會碰到這個問題發生。我還是覺得用一條線程去發就好了…
作者: lovdkkkk (dk)   2016-04-09 20:56:00
同樓上, 一條慢慢的一封一封寄就好了 @@
作者: brucetu (sec)   2016-04-09 21:57:00
只用一條線程循環處理所有要寄的信 也不會多慢吧,絕對比現在五秒發一封快,不然就是好好檢查把資料傳遞切乾淨,也許其他客戶沒有出問題是因為他們沒發現?例如根本沒有check或者訊息內容非常雷同 寄錯人也不會發現
作者: psliurt (反指標)   2016-04-10 12:48:00
哀 問題就是那個static smtpclient我覺得你先把執行緒跟何謂執行緒安全搞清楚
作者: YahooTaiwan (超可愛南西我老婆)   2016-04-10 19:02:00
既然每次送信都要 new smtpclient,幹嘛放 static ???感覺你不是很了解 static 的特性與用途

Links booklink

Contact Us: admin [ a t ] ucptt.com