У меня проблема с тем, что когда мы инициируем ресурс REST от третьей стороны (Twilio), служба реагирует так быстро, что у нас нет времени записывать наши SID в базу данных. Мы не можем сказать службе ждать, так как она возвращает SID, только когда служба инициирована. Само приложение не может содержать состояние, поскольку нет гарантии, что обратный вызов RESTful достигнет того же экземпляра нашего приложения.
Мы уменьшили проблему, записав идентификаторы безопасности в буферную таблицу в базе данных, и мы попробовали несколько стратегий, чтобы заставить веб-ответ ждать, но использование Thread.Sleep, похоже, блокирует другие не связанные с ним веб-ответы и как правило, замедляет работу сервера во время пиковой нагрузки.
Как я могу изящно попросить веб-ответ подождать минуту, пока мы проверяем базу данных? Желательно, не засоряя весь сервер заблокированными потоками.
Это код, который инициирует услугу:
private static void SendSMS(Shift_Offer so, Callout co,testdb2Entities5 db)
{
co.status = CalloutStatus.inprogress;
db.SaveChanges();
try
{
CallQueue cq = new CallQueue();
cq.offer_id = so.shift_offer_id;
cq.offer_finished = false;
string ShMessage = getNewShiftMessage(so, co, db);
so.offer_timestamp = DateTime.Now;
string ServiceSID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var message = MessageResource.Create
(
body: ShMessage,
messagingServiceSid: ServiceSID,
to: new Twilio.Types.PhoneNumber(RCHStringHelpers.formatPhoneNumber(so.employee_phone_number)),
statusCallback: new Uri(TwilioCallBotController.SMSCallBackURL)
);
cq.twilio_sid = message.Sid;
db.CallQueues.Add(cq);
db.SaveChanges();
so.offer_status = ShiftOfferStatus.OfferInProgress;
so.status = message.Status.ToString();
so.twillio_sid = message.Sid;
db.SaveChanges();
}
catch (SqlException e) //if we run into any problems here, release the lock to prevent stalling;
//note to self - this should all be wrapped in a transaction and rolled back on error
{
Debug.WriteLine("Failure in CalloutManager.cs at method SendSMS: /n" +
"Callout Id: " + co.callout_id_pk + "/n"
+ "Shift Offer Id: " + so.shift_offer_id + "/n"
+ e.StackTrace);
ResetCalloutStatus(co, db);
ReleaseLock(co, db);
}
catch (Twilio.Exceptions.ApiException e)
{
ReleaseLock(co, db);
ResetCalloutStatus(co, db);
Debug.WriteLine(e.Message + "/n" + e.StackTrace);
}
}
Это код, который отвечает:
public ActionResult TwilioSMSCallback()
{
//invalid operation exception occurring here
string sid = Request.Form["SmsSid"];
string status = Request.Form["SmsStatus"];
Shift_Offer shoffer;
CallQueue cq = null;
List<Shift_Offer> sho = db.Shift_Offers.Where(s => s.twillio_sid == sid).ToList();
List<CallQueue> cqi = getCallQueueItems(sid, db);
if (sho.Count > 0)
{
shoffer = sho.First();
if (cqi.Count > 0)
{
cq = cqi.First();
}
}
else
{
if (cqi.Count > 0)
{
cq = cqi.First();
shoffer = db.Shift_Offers.Where(x => x.shift_offer_id == cq.offer_id).ToList().First();
}
else
{
return new Twilio.AspNet.Mvc.HttpStatusCodeResult(HttpStatusCode.NoContent);
}
}
Callout co = db.Callouts.Where(s => s.callout_id_pk == shoffer.callout_id_fk).ToList().First();
shoffer.status = status;
if (status.Contains("accepted"))
{
shoffer.offer_timestamp = DateTime.Now;
shoffer.offer_status = ShiftOfferStatus.SMSAccepted + " " + DateTime.Now;
}
else if (status.Contains("queued") || status.Contains("sending"))
{
shoffer.offer_timestamp = DateTime.Now;
shoffer.offer_status = ShiftOfferStatus.SMSSent + " " + DateTime.Now;
}
else if (status.Contains("delivered") || status.Contains("sent"))
{
shoffer.offer_timestamp = DateTime.Now;
shoffer.offer_status = ShiftOfferStatus.SMSDelivered + " " + DateTime.Now;
setStatus(co);
if (cq != null){
cq.offer_finished = true;
}
CalloutManager.ReleaseLock(co, db);
}
else if (status.Contains("undelivered"))
{
shoffer.offer_status = ShiftOfferStatus.Failed + " " + DateTime.Now;
setStatus(co);
if (cq != null){
cq.offer_finished = true;
}
CalloutManager.ReleaseLock(co, db);
}
else if (status.Contains("failed"))
{
shoffer.offer_status = ShiftOfferStatus.Failed + " " + DateTime.Now;
setStatus(co);
if (cq != null){
cq.offer_finished = true;
}
cq.offer_finished = true;
CalloutManager.ReleaseLock(co, db);
}
db.SaveChanges();
return new Twilio.AspNet.Mvc.HttpStatusCodeResult(HttpStatusCode.OK);
}
Это код, который задерживает:
public static List<CallQueue> getCallQueueItems(string twilioSID, testdb2Entities5 db)
{
List<CallQueue> cqItems = new List<CallQueue>();
int retryCount = 0;
while (retryCount < 100)
{
cqItems = db.CallQueues.Where(x => x.twilio_sid == twilioSID).ToList();
if (cqItems.Count > 0)
{
return cqItems;
}
Thread.Sleep(100);
retryCount++;
}
return cqItems;
}