octokit.graphql.net icon indicating copy to clipboard operation
octokit.graphql.net copied to clipboard

🚀🚀🚀 TransferAllIssues -> parallel foreach async -> MAGIC :) 🚀🚀🚀

Open p-bojkowski opened this issue 4 years ago • 0 comments

Hi! Maybe someone will need this too - or can implement in octokit.graphql.net.

Adding some parallel foreach async MAGIC :)

public async Task<bool> TransferAllIssues(string fromRepositoryName, string toRepositoryId, string pemKey)
{
	var issueIDs = await GetAllIssuesFromRepository(fromRepositoryName, pemKey);

	// Async Parallel Foreach in C# -> check extension
	issueIDs.AsyncParallelForEach(async issueId =>
	{
		await TransferIssue(issueId, toRepositoryId, pemKey);
	}, 100, TaskScheduler.FromCurrentSynchronizationContext());

	return true;
}
public async Task<string> TransferIssue(string issueId, string toRepositoryId, string pemKey)
{
	_pemKey = pemKey;
	var connection = await GetGraphQlConnection();

	var mutation = new Mutation()
		.TransferIssue(new TransferIssueInput()
			{
				IssueId = new ID(issueId),
				RepositoryId = new ID(toRepositoryId)
			}
		)
		.Select(payload => new {payload.Issue.Id})
		.Compile();

	if (connection != null)
	{
		var result = await connection.Run(mutation);

		return result.Id.Value;
	}
	else
	{
		// TODO
		return "ERROR!!!!!!!!!!!!!!!!!";
	}
}
public async Task<IEnumerable<string>> GetAllIssuesFromRepository(string repositoryName, string pemKey)
{
	_pemKey = pemKey;
	var connection = await GetGraphQlConnection();
	
	var query = new Query()
		.RepositoryOwner(StaticData.Organization)
		.Repository(repositoryName)
		.Issues() // OR with paging: Issues = r.Issues(100, null, null, null, null, null, null, null) + .Nodes -> without AllPages()
		.AllPages() // Auto-pages Issues
		.Select(issue => new
		{
			issue.Id
		}).Compile();

	if (connection != null)
	{
		var result = await connection.Run(query);
		IEnumerable<string> issueIDs = result.Select(i => i.Id.Value);

		return issueIDs;
	}
	else
	{
		// TODO
		return null;
	}
}
//
// Parallel Foreach async in C#
// Optimizing Parallel async Foreach with C# 8.0 async streams
// https://scatteredcode.net/parallel-foreach-async-in-c/
//
//
//                                |                         Method |     Mean |   Error |  StdDev | Ratio | RatioSD |
//                                |------------------------------- |---------:|--------:|--------:|------:|--------:|
//                                |                         Linear | 244.07 s | 5.703 s | 8.879 s |  1.00 |    0.00 |
//                                |                   ForEachAsync |  30.84 s | 1.899 s | 5.324 s |  0.11 |    0.01 |
//                                |                   AsyncForEach | 272.10 s | 5.435 s | 8.620 s |  1.12 |    0.05 |
//                                |           ParallelForEachAsync |  26.53 s | 0.339 s | 0.317 s |  0.11 |    0.00 |
// we are using this --> :) -->   |           AsyncParallelForEach |  25.79 s | 0.490 s | 0.564 s |  0.10 |    0.00 |
//                                | AsyncEnumerableParallelForEach |  24.67 s | 0.436 s | 0.408 s |  0.10 |    0.00 |
//
public static Task AsyncParallelForEach<T>(this IEnumerable<T> source, Func<T, Task> body, int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded, TaskScheduler scheduler = null)
{
	var options = new ExecutionDataflowBlockOptions
	{
		MaxDegreeOfParallelism = maxDegreeOfParallelism
	};
	if (scheduler != null)
		options.TaskScheduler = scheduler;
	var block = new ActionBlock<T>(body, options);
	foreach (var item in source)
		block.Post(item);
	block.Complete();
	return block.Completion;
}

p-bojkowski avatar Apr 10 '21 12:04 p-bojkowski