Populate mails in batches and process batch by batch instead of sending mail one by one, this provides better scalability and also have more control on the usage of number of threads {cancellation[if required]}.
For example:
Number of emails to send: 103
BatchSize :5 (Make it configurable)
We have in total : 20 batches of size 5 and 1 batch of size 3
Steps are as follows
a. Process first batch.
b. Wait till batch completes execution
c. Take next batch for process
d. Repeat the process till all the batches.
I have two approaches to achieve this, based on the requirement you can use any of the approach
Use async/await and Task => Create separate task for sending each mail in each batch, which uses multiple threads.
Process Batch 1 => 5 users, Create 5 tasks and execute
=> Wait for all tasks to complete
Process Batch 2 => 5 users, Create 5 tasks and execute
=> Wait for all tasks to complete
...
Use only async/await => which will use almost same thread for processing.
Consider the Email Class as below, and _batchSize
public class EmailClass
{
public string Email { get; set; }
public string Message { get; set; }
public string Subject { get; set; }
}
private int _batchSize = 5;
List<EmailClass> _emailCollection = new List<EmailClass>();
When the user clicks on Send button
private async void button_Click(object sender, RoutedEventArgs e)
{
for (int ii = 0; ii < 22; ii++)
{
_emailCollection.Add(new EmailClass()
{
Email = "Email_" + ii + "@gmail.com",
Message = "http://google.com",
Subject = "Subject_" + ii
});
}
await SendBulkMail();
}
Divide the whole bunch of mails, into chunks of _batchSize, process each chunk one by one.
private async Task SendBulkMail()
{
int remainingBatches = _emailCollection.Count % _batchSize;
int numberOfBatches = (_emailCollection.Count - remainingBatches) / _batchSize;
Debug.WriteLine(string.Format("TotalCount:{0} NumberOfBatches:{1}", _emailCollection.Count, numberOfBatches));
for (int ii = 0; ii < numberOfBatches; ii++)
{
Debug.WriteLine(DateTime.Now.ToString() + " CurrentChunk : " + ii);
await SendBatchMail(0, ii, _batchSize);
}
if (remainingBatches != 0)
{
await SendBatchMail(_emailCollection.Count - remainingBatches, 0, _emailCollection.Count);
}
}
Solution 1: Create Task for each mail while processing each block
private async Task SendBatchMail(int initalIndex, int batchIndex, int size)
{
List<Task> chunkTasks = new List<Task>();
chunkTasks.Clear();
for (int jj = initalIndex; jj < size; jj++)
{
var index = _batchSize * batchIndex + jj;
chunkTasks.Add(Task.Factory.StartNew(() => {
SendEmailAsync(_emailCollection[index].Email, _emailCollection[index].Subject, _emailCollection[index].Message);
}));
}
await Task.Run(() =>
{
Task.WaitAll(chunkTasks.ToArray());
});
}
public void SendEmailAsync(string email, string subject, string message)
{
Debug.WriteLine("\t" + DateTime.Now.ToString() + " " + Thread.CurrentThread.ManagedThreadId + " Sending mail : " + email);
try
{
SendMessage(email + subject + message);
}
catch (Exception ex)
{
}
}
private void SendMessage(string message)
{
Debug.WriteLine("\t\t" + DateTime.Now.ToString() + " " +Thread.CurrentThread.ManagedThreadId + " Message sending : => " + message);
int sleepTime = new Random().Next(5) * 1000;
Thread.Sleep(sleepTime);
Debug.WriteLine("\t\t" + DateTime.Now.ToString() + " " +Thread.CurrentThread.ManagedThreadId + " Message sent : => " + message);
}
Solution 1 output : Separate threads[may or may not] is used for sending each mail in every batch
TotalCount:22 NumberOfBatches:4
4/12/2018 11:07:02 PM CurrentChunk : 0
4/12/2018 11:07:02 PM 13 Sending mail : [email protected]
4/12/2018 11:07:02 PM 15 Sending mail : [email protected]
4/12/2018 11:07:02 PM 15 Message sending : => [email protected]_1http://google.com
4/12/2018 11:07:02 PM 11 Sending mail : [email protected]
4/12/2018 11:07:02 PM 11 Message sending : => [email protected]_2http://google.com
4/12/2018 11:07:02 PM 13 Message sending : => [email protected]_0http://google.com
4/12/2018 11:07:02 PM 14 Sending mail : [email protected]
4/12/2018 11:07:02 PM 14 Message sending : => [email protected]_3http://google.com
4/12/2018 11:07:02 PM 14 Message sent : => [email protected]_3http://google.com
4/12/2018 11:07:02 PM 14 Sending mail : [email protected]
4/12/2018 11:07:02 PM 14 Message sending : => [email protected]_4http://google.com
4/12/2018 11:07:02 PM 14 Message sent : => [email protected]_4http://google.com
4/12/2018 11:07:05 PM 15 Message sent : => [email protected]_1http://google.com
4/12/2018 11:07:05 PM 11 Message sent : => [email protected]_2http://google.com
4/12/2018 11:07:05 PM 13 Message sent : => [email protected]_0http://google.com
4/12/2018 11:07:05 PM CurrentChunk : 1
4/12/2018 11:07:05 PM 16 Sending mail : [email protected]
4/12/2018 11:07:05 PM 14 Sending mail : [email protected]
4/12/2018 11:07:05 PM 13 Sending mail : [email protected]
4/12/2018 11:07:06 PM 15 Sending mail : [email protected]
4/12/2018 11:07:06 PM 15 Message sending : => [email protected]_8http://google.com
4/12/2018 11:07:06 PM 11 Sending mail : [email protected]
4/12/2018 11:07:06 PM 11 Message sending : => [email protected]_9http://google.com
4/12/2018 11:07:06 PM 14 Message sending : => [email protected]_7http://google.com
4/12/2018 11:07:06 PM 13 Message sending : => [email protected]_6http://google.com
4/12/2018 11:07:06 PM 15 Message sent : => [email protected]_8http://google.com
4/12/2018 11:07:06 PM 16 Message sending : => [email protected]_5http://google.com
4/12/2018 11:07:06 PM 16 Message sent : => [email protected]_5http://google.com
4/12/2018 11:07:10 PM 11 Message sent : => [email protected]_9http://google.com
4/12/2018 11:07:10 PM 14 Message sent : => [email protected]_7http://google.com
4/12/2018 11:07:10 PM 13 Message sent : => [email protected]_6http://google.com
Solution 2 : Use only async/await pattern
private async Task SendBatchMail(int initalIndex, int batchIndex, int size)
{
List<Task> chunkTasks = new List<Task>();
chunkTasks.Clear();
for (int jj = initalIndex; jj < size; jj++)
{
var index = _batchSize * batchIndex + jj;
chunkTasks.Add(SendEmailAsync(_emailCollection[index].Email, _emailCollection[index].Subject, _emailCollection[index].Message));
}
await Task.Run(() =>
{
Task.WaitAll(chunkTasks.ToArray());
});
}
public async Task SendEmailAsync(string email, string subject, string message)
{
Debug.WriteLine("\t" + DateTime.Now.ToString() + " " + Thread.CurrentThread.ManagedThreadId + " Sending mail : " + email);
try
{
await SendMessage(email + subject + message);
}
catch (Exception ex)
{
}
}
private async Task SendMessage(string message)
{
Debug.WriteLine("\t\t" + DateTime.Now.ToString() + " " +Thread.CurrentThread.ManagedThreadId + " Message sending : => " + message);
await Task.Run(() =>
{
int sleepTime = new Random().Next(5) * 1000;
Thread.Sleep(sleepTime);
});
Debug.WriteLine("\t\t" + DateTime.Now.ToString() + " " +Thread.CurrentThread.ManagedThreadId + " Message sent : => " + message);
}
Solution 2 Output (Almost one thread is used for processing of all batches)
4/12/2018 11:01:05 PM CurrentChunk : 0
4/12/2018 11:01:05 PM 10 Sending mail : [email protected]
4/12/2018 11:01:05 PM 10 Message sending : => [email protected]_0http://google.com
4/12/2018 11:01:05 PM 10 Sending mail : [email protected]
4/12/2018 11:01:05 PM 10 Message sending : => [email protected]_1http://google.com
4/12/2018 11:01:05 PM 10 Sending mail : [email protected]
4/12/2018 11:01:05 PM 10 Message sending : => [email protected]_2http://google.com
4/12/2018 11:01:05 PM 10 Sending mail : [email protected]
4/12/2018 11:01:05 PM 10 Message sending : => [email protected]_3http://google.com
4/12/2018 11:01:05 PM 10 Sending mail : [email protected]
4/12/2018 11:01:05 PM 10 Message sending : => [email protected]_4http://google.com
4/12/2018 11:01:05 PM 10 Message sent : => [email protected]_2http://google.com
4/12/2018 11:01:05 PM 10 Message sent : => [email protected]_3http://google.com
4/12/2018 11:01:05 PM 10 Message sent : => [email protected]_4http://google.com
4/12/2018 11:01:08 PM 10 Message sent : => [email protected]_0http://google.com
4/12/2018 11:01:08 PM 10 Message sent : => [email protected]_1http://google.com
4/12/2018 11:01:08 PM CurrentChunk : 1
4/12/2018 11:01:08 PM 10 Sending mail : [email protected]
4/12/2018 11:01:08 PM 10 Message sending : => [email protected]_5http://google.com
4/12/2018 11:01:08 PM 10 Sending mail : [email protected]
4/12/2018 11:01:08 PM 10 Message sending : => [email protected]_6http://google.com
4/12/2018 11:01:08 PM 10 Sending mail : [email protected]
4/12/2018 11:01:08 PM 10 Message sending : => [email protected]_7http://google.com
4/12/2018 11:01:08 PM 10 Sending mail : [email protected]
4/12/2018 11:01:08 PM 10 Message sending : => [email protected]_8http://google.com
4/12/2018 11:01:08 PM 10 Sending mail : [email protected]
4/12/2018 11:01:08 PM 10 Message sending : => [email protected]_9http://google.com
4/12/2018 11:01:09 PM 10 Message sent : => [email protected]_9http://google.com
4/12/2018 11:01:10 PM 10 Message sent : => [email protected]_7http://google.com
4/12/2018 11:01:10 PM 10 Message sent : => [email protected]_8http://google.com
4/12/2018 11:01:11 PM 10 Message sent : => [email protected]_5http://google.com
4/12/2018 11:01:12 PM 10 Message sent : => [email protected]_6http://google.com