I have an application that is notifying each subscriber in our SMS database of an update to our system. It uses the entity framework to select each record and then creates a new Task to send a message to that person. Theoretically, this should be a fast process. I'm doing something wrong because it is only getting one complete response every second or two.
I think that the problem has to do with the way I'm setting up the Tasks in Task.Factory.StartNew()
. It is acting like it is running synchronously, but I want it to run asynchronously.
If I am completely off-base with how I am using Tasks, please let me know. I got my inspiration from this post.
Here's my code:
class Program
{
static List<MessageToSend> Messages = new List<MessageToSend>();
static Entities oDatabase = new Entities();
static SMS.API oAPI = new SMS.API();
const string sAuthToken = "*****";
const string sNotificationMessage = "*****";
static void Main(string[] args)
{
foreach (var subscriber in oDatabase.SMS_Subscribers.Where(x => x.GlobalOptOut == false))
{
MessageToSend oMessage = new MessageToSend();
oMessage.ID = subscriber.ID;
oMessage.MobileNumber = subscriber.MobileNumber;
var recentlySentMessage = oDatabase.SMS_OutgoingMessages.Where(x => x.Message == sNotificationMessage && x.MobileNumber == oMessage.MobileNumber && x.Sent > new DateTime(2014, 3, 12)).FirstOrDefault();
if (recentlySentMessage != null)
{
oMessage.Completed = true;
continue;
}
Task t = Task.Factory.StartNew(() =>
{
try{
var keywordID = oDatabase.SMS_SubscribersKeywords.Where(x => x.SubscriberID == oMessage.ID).First().KeywordID;
var keyword = oDatabase.SMS_Keywords.Where(x => x.ID == keywordID).First();
oMessage.DemographicID = keyword.DemographicID;
oMessage.Keyword = keyword.Keyword;
SendNotificationMessage(oMessage);
}
catch (Exception oEx){ //Write exception to console}
});
Thread.Sleep(15);
}
while (Messages.ToList().Any(x => !x.Completed)){ //wait till all are completed}
}
public static void SendNotificationMessage(object message)
{
MessageToSend oMessage = (MessageToSend)message;
try
{
SMS.APIResponse oResponse = oAPI.SendMessage(sAuthToken, oMessage.DemographicID, oMessage.Keyword, oMessage.MobileNumber, sNotificationMessage);
if (oResponse.Success){ //Write success to console }
else{ //Write failure to console }
}
catch (Exception oEx){ //Write Exception to console }
oMessage.Completed = true;
}
}
class MessageToSend
{
public long ID { get; set; }
public long DemographicID {get;set;}
public string MobileNumber { get; set; }
public bool Completed { get; set; }
public string Keyword { get; set; }
public MessageToSend(){ Completed = false; }
}
EDIT: The inside of the foreach block now looks like this:
MessageToSend oMessage = new MessageToSend();
oMessage.ID = subscriber.ID;
oMessage.MobileNumber = subscriber.MobileNumber;
int keywordID = 0;
SMSShortcodeMover.SMS_Keywords keyword;
var recentlySentMessage = oDatabase.SMS_OutgoingMessages.Where(x => x.Message == sNotificationMessage && x.MobileNumber == oMessage.MobileNumber && x.Sent > new DateTime(2014, 3, 12)).FirstOrDefault();
if (recentlySentMessage != null)
{
oMessage.Completed = true;
continue;
}
try
{
keywordID = (int)oDatabase.SMS_SubscribersKeywords.Where(x => x.SubscriberID == oMessage.ID).First().KeywordID;
keyword = oDatabase.SMS_Keywords.Where(x => x.ID == keywordID).First();
} catch (Exception oEx){ //write exception to console, then continue; }
Task t = Task.Factory.StartNew(() =>
{
oMessage.DemographicID = keyword.DemographicID;
oMessage.Keyword = keyword.Keyword;
SendNotificationMessage(oMessage);
});
Thread.Sleep(15);
}
EDIT 2: I updated my code again, now I gather all of my data before I go into the send. It still is hanging somewhere, but it gets all 52,000 rows of data in about 5 seconds now. The code looks like this:
var query =
(from subscriber in oDatabase.SMS_Subscribers
where subscriber.GlobalOptOut == false
where !(from x in oDatabase.SMS_OutgoingMessages
where x.Message == sNotificationMessage
where x.MobileNumber == subscriber.MobileNumber
where x.Sent > new DateTime(2014, 3, 12)
select x).Any()
join sk in oDatabase.SMS_SubscribersKeywords
on subscriber.ID equals sk.SubscriberID
join k in oDatabase.SMS_Keywords on sk.KeywordID equals k.ID into ks
from k2 in ks.Take(1)
select new MessageToSend()
{
ID = subscriber.ID,
MobileNumber = subscriber.MobileNumber,
DemographicID = k2.DemographicID,
Keyword = k2.Keyword
}).ToList();
foreach( var q in query){
Task t = Task.Factory.StartNew(() => SendNotificationMessage(q));
Tasks.Add(t);
Thread.Sleep(80);
}
Task.WaitAll(Tasks.ToArray());