I have a script that calls api endpoints but when it does something strange is happening I can't even explain it so I'll show you the code and explain the result I am getting.
public class Program
{
private static OpenSeaApiClient openSeaApiClient;
private static Timer timer;
private static int counter = 1;
private static Collection galaxyEggs9999;
static async Task Main()
{
string apiKey = "myKey";
openSeaApiClient = new OpenSeaApiClient(apiKey);
// Set up a timer to run the API calls every 10 seconds
timer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
timer.Elapsed += async (sender, e) => await TimerElapsedAsync();
timer.Start();
Console.WriteLine("Press Enter to exit.");
Console.ReadKey();
// Stop the timer when exiting the program
timer.Stop();
timer.Dispose();
}
private static async Task TimerElapsedAsync()
{
Console.WriteLine($"Counter: {counter++}");
if (galaxyEggs9999 == null)
{
galaxyEggs9999 = new Collection(openSeaApiClient, "galaxyeggs9999", "0xA08126f5E1ED91A635987071E6FF5EB2aEb67C48");
}
await galaxyEggs9999.ExecuteAsync();
//more instances
}
So TimerElapsedAsync() is set up with a Timer. When TimerElapsedAsync() starts 1 is printed and the script goes in the first instance of object. This object looks like that:
public class Collection
{
private readonly OpenSeaApiClient openSeaApiClient;
private readonly string collectionName;
private readonly string collectionContractAddress;
public Collection(OpenSeaApiClient openSeaApiClient, string collectionName, string collectionContractAddress)
{
this.openSeaApiClient = openSeaApiClient;
this.collectionName = collectionName;
this.collectionContractAddress = collectionContractAddress;
}
public async Task ExecuteAsync()
{
//more code
}
else
{
var bestListingsResponse = await openSeaApiClient.GetBestListingsInCollectionResponse(CollectionName);
floorPriceInEtherDouble = GetCollectionFloorPriceInEther(bestListingsResponse);
//more code
Here comes the issue - when the script reaches
var bestListingsResponse = await openSeaApiClient.GetBestListingsInCollectionResponse(CollectionName);
2 is printed, after that 3,4,5 before the script continue with the other lines. And if I put a breakpoint on GetBestListingsInCollectionResponse() and press Step Over it just keeps printing incrementing numbers and not continuing.
This is what GetBestListingsInCollectionResponse() looks like if this is of any help.
public async Task<string> GetBestListingsInCollectionResponse(string collectionSlug)
{
string endpoint = $"api/v2/listings/collection/{collectionSlug}/best";
return await SendGetRequest(endpoint);
}
I have more endpoints in my code and they all keep doing weird things like executing themselves multiple times.
Why is this happening?
Based on the API used you are running System.Timers.Timer
, and from the Remarks section of the docs:
The
Timer
component is a server-based timer that raises anElapsed
event in your application after the number of milliseconds in theInterval
property has elapsed. You can configure theTimer
object to raise the event just once or repeatedly using theAutoReset
property.
So it will not wait for the handler to complete and will raise the event every time the interval has elapsed.
One workaround can be to set AutoReset
to false and then enable the timer in the handler when it completes:
timer.AutoReset = false;
timer.Elapsed += (sender, eventArgs) =>
{
Thread.Sleep(1000); // simulate some work
Console.WriteLine("elapsed"); // simulate some work
timer.Enabled = true; // do not forget to handle the exceptions
};
But since .NET 6 you can leverage the System.Threading.PeriodicTimer
which is designed for such use-cases (for example leveraging it in ASP.NET Core background workers - see here).