Skip to content

Commit

Permalink
Merge pull request #193 from sebader/dev
Browse files Browse the repository at this point in the history
Update data fetchers to net8
  • Loading branch information
sebader authored Apr 27, 2024
2 parents 5af6627 + eb52103 commit 6786cff
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 210 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/azure-fetchdata-functions-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ on:
env:
AZURE_FUNCTIONAPP_NAME: alpinehutsdatafetcher # set this to your application's name
AZURE_FUNCTIONAPP_PACKAGE_PATH: './FetchDataFunctions' # set this to the path to your web app project, defaults to the repository root
DOTNET_VERSION: '6.x' # set this to the dotnet version to use
DOTNET_VERSION: '8.x' # set this to the dotnet version to use

jobs:
function_build_and_deploy:
runs-on: windows-latest
steps:
- name: 'Checkout GitHub Action'
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup DotNet ${{ env.DOTNET_VERSION }} Environment
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

Expand Down
33 changes: 19 additions & 14 deletions FetchDataFunctions/CleanupFreeBedNotificationSubscriptions.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using FetchDataFunctions.Models;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Extensions.Sql;
using Microsoft.Extensions.Logging;

namespace FetchDataFunctions.WebsiteFunctions
namespace FetchDataFunctions
{
public class CleanupFreeBedNotificationSubscriptions
{
private readonly ILogger<CleanupFreeBedNotificationSubscriptions> _logger;

public CleanupFreeBedNotificationSubscriptions(ILogger<CleanupFreeBedNotificationSubscriptions> logger)
{
_logger = logger;
}

/// <summary>
/// On execution, it runs the cleanup stored procedure in the database which removes
/// any free bed notification subscriptions which are now in the past
/// </summary>
/// <param name="myTimer"></param>
/// <param name="result"></param>
/// <param name="log"></param>
[FunctionName(nameof(CleanupFreeBedNotificationSubscriptions))]
public void Run([TimerTrigger("0 0 1 * * * ")]TimerInfo myTimer,
[Sql("[dbo].[DeleteOldFreeBedSubscriptions]",
"DatabaseConnectionString",
CommandType.StoredProcedure)] IEnumerable<FreeBedUpdateSubscription> result,
ILogger log)
[Function(nameof(CleanupFreeBedNotificationSubscriptions))]
public void Run([TimerTrigger("0 0 1 * * * ")] TimerInfo myTimer,
[SqlInput("[dbo].[DeleteOldFreeBedSubscriptions]",
"DatabaseConnectionString",
CommandType.StoredProcedure, "")]
IEnumerable<FreeBedUpdateSubscription> result)
{
log.LogInformation($"Free bed subscription cleanup timer trigger function executed at: {DateTime.Now}");
log.LogInformation($"Now {result.Count()} subscriptions are left in the database");
_logger.LogInformation("Free bed subscription cleanup timer trigger function executed");
_logger.LogInformation($"Now {result.Count()} subscriptions are left in the database");
}
}
}
}
31 changes: 21 additions & 10 deletions FetchDataFunctions/FetchDataFunctions.csproj
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.60" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions" Version="5.0.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.13.2" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask.Analyzers" Version="0.5.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Http" Version="3.2.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.SendGrid" Version="3.0.3" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Sql" Version="3.0.534" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="5.2.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.22.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.SendGrid" Version="3.0.3" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Sql" Version="3.0.534" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage" Version="6.4.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Timer" Version="4.3.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.28" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.28" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.3.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.4" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.4" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
Expand All @@ -27,4 +34,8 @@
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>

<ItemGroup>
<Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext"/>
</ItemGroup>
</Project>
15 changes: 8 additions & 7 deletions FetchDataFunctions/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

Expand Down Expand Up @@ -55,7 +56,7 @@ public static AlpinehutsDbContext GetDbContext()
/// <param name="isNewHut"></param>
/// <param name="log"></param>
/// <returns></returns>
public static async Task<Hut> ParseHutInformation(int hutId, HtmlDocument doc, bool isNewHut, HttpClient httpClient, ILogger log)
public static async Task<Hut?> ParseHutInformation(int hutId, HtmlDocument doc, bool isNewHut, HttpClient httpClient, ILogger log)
{
var infoDiv = doc.DocumentNode.SelectSingleNode("//body").Descendants("div").Where(d => d.Attributes.Contains("class") && d.Attributes["class"].Value == "info").FirstOrDefault();
if (infoDiv != null)
Expand Down Expand Up @@ -90,8 +91,8 @@ public static async Task<Hut> ParseHutInformation(int hutId, HtmlDocument doc, b
}
hut.Enabled = !doc.ParsedText.Contains("Diese Hütte ist nicht freigeschaltet");

string country = null;
string region = null;
string? country = null;
string? region = null;

// Only call the external services, if the hut is a new one for us
if (isNewHut)
Expand Down Expand Up @@ -175,7 +176,7 @@ private static string GetCountry(string hutName, string phoneNumber, string requ
public static async Task<(double? latitude, double? longitude)> SearchHutCoordinates(string hutName, HttpClient httpClient, ILogger log)
{
const string baseSearchUrl = "https://nominatim.openstreetmap.org/search.php?format=json&limit=5";
string searchUrl = null;
string? searchUrl = null;
try
{
// Most hut names contain the Section after a comma. We only use the name for the search
Expand All @@ -190,7 +191,7 @@ private static string GetCountry(string hutName, string phoneNumber, string requ
var result = await httpClient.GetAsync(searchUrl);
result.EnsureSuccessStatusCode();

var searchResults = await result.Content.ReadAsAsync<List<NominatimSearchResult>>();
var searchResults = await result.Content.ReadFromJsonAsync<List<NominatimSearchResult>>();
if (searchResults?.Count > 0)
{
NominatimSearchResult sr = null;
Expand Down Expand Up @@ -255,7 +256,7 @@ private static string GetCountry(string hutName, string phoneNumber, string requ
/// <param name="longitude"></param>
/// <param name="log"></param>
/// <returns></returns>
public static async Task<(string country, string region)> GetCountryAndRegion(double latitude, double longitude, HttpClient httpClient, ILogger log)
public static async Task<(string? country, string? region)> GetCountryAndRegion(double latitude, double longitude, HttpClient httpClient, ILogger log)
{
const string baseSearchUrl = "https://atlas.microsoft.com/search/address/reverse/json?api-version=1.0&language=de";

Expand All @@ -271,7 +272,7 @@ private static string GetCountry(string hutName, string phoneNumber, string requ
var result = await httpClient.GetAsync(searchUrl);
result.EnsureSuccessStatusCode();

var searchResult = await result.Content.ReadAsAsync<AzureMapsResult>();
var searchResult = await result.Content.ReadFromJsonAsync<AzureMapsResult>();
if (searchResult?.addresses?.Length > 0)
{
var address = searchResult.addresses.First().address;
Expand Down
62 changes: 62 additions & 0 deletions FetchDataFunctions/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Polly;
using Polly.Extensions.Http;
using Polly.Timeout;

namespace FetchDataFunctions;

public class Program
{
public static void Main(string[] args)
{
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services =>
{
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();

services
.AddHttpClient<HttpClient>("HttpClient", client =>
{
var productValue = new ProductInfoHeaderValue("HutInfoScraperBot", "1.0");
client.DefaultRequestHeaders.UserAgent.Add(productValue);

client.Timeout =
TimeSpan.FromSeconds(
120); // default overall request request timeout (includes all polly retries)
})
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies =
false, // Prevent cookie sharing in multi thread env https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0#cookies
};
})
.AddPolicyHandler(GetRetryWithTimeoutPolicy());
})
.Build();

host.Run();
}

static IAsyncPolicy<HttpResponseMessage> GetRetryWithTimeoutPolicy()
{
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg =>
msg.StatusCode ==
System.Net.HttpStatusCode.Forbidden) // Retry 403 as it seems to be some rate limiting error
.Or<TimeoutRejectedException>()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
.WrapAsync(Policy.TimeoutAsync(30)); // per request timeout

return retryPolicy;
}
}
48 changes: 0 additions & 48 deletions FetchDataFunctions/Startup.cs

This file was deleted.

Loading

0 comments on commit 6786cff

Please sign in to comment.