public async Task HandleSupporterCheckoutCompletedAsync(Session session, CancellationToken cancellationToken = default) { var duration = session.Metadata.TryGetValue("duration", out var x) && long.TryParse(x, out var y) ? y : 0; var amount = session.Metadata.TryGetValue("amount", out var z) && double.TryParse(z, out var w) ? w : 0; if (duration == 0) { return; // this shouldn't happen } var now = DateTime.UtcNow; await using (await _writeControl.EnterAsync(cancellationToken)) { var result = await _users.AddSupporterDurationAsync(session.ClientReferenceId, TimeSpan.FromDays(duration / 12.0 * 365.2422), amount, cancellationToken); if (result.IsT0) { await AddDonationProgress(now, amount, cancellationToken); } else { throw new Exception($"User {session.ClientReferenceId} could not be found."); } } }
protected sealed override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { try { if (!Enabled) { goto sleep; } await using (await _writeControl.EnterAsync(stoppingToken)) await using (await _locker.EnterAsync($"scrape:{Type}", stoppingToken)) { _logger.LogDebug($"Begin {Type} scrape."); // run tests before scrape await TestAsync(stoppingToken); // load last state from storage var state = await _storage.ReadObjectAsync <TState>($"scrapers/{Type}/state", stoppingToken) ?? new TState(); // execute scraper using (ScraperMetrics.ScrapingTime.Labels(Type.ToString()).Measure()) await RunAsync(state, stoppingToken); // save state await _storage.WriteObjectAsync($"scrapers/{Type}/state", state, stoppingToken); if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug($"Saved scraper state {Type}: {JsonConvert.SerializeObject(state)}"); } _logger.LogDebug($"End {Type} scrape."); } } catch (Exception e) { SentrySdk.CaptureException(e); ScraperMetrics.ScrapeErrors.Labels(Type.ToString()).Inc(); _logger.LogWarning(e, $"Exception while scraping {Type}."); } sleep: await Task.Delay(_options.CurrentValue.Interval, stoppingToken); } }