Skip to content

Commit

Permalink
本来はロサンゼルス標準時で計算しなければならなかったので修正した
Browse files Browse the repository at this point in the history
  • Loading branch information
tumugin committed Feb 13, 2024
1 parent 552a5bf commit 40b55fc
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 29 deletions.
6 changes: 6 additions & 0 deletions GCPCostNotifier/Log.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ namespace GCPCostNotifier;

public static partial class Log
{
[LoggerMessage(
message: "Triggered function. The target timezone is `{timezone}` and IsDaylightSavingTime is `{isDaylightSavingTime}`",
level: LogLevel.Information
)]
public static partial void TriggeredFunction(ILogger logger, string timeZone, bool isDaylightSavingTime);

[LoggerMessage(message: "Initializing BigQuery client.", level: LogLevel.Information)]
public static partial void InitializingBigQueryClient(ILogger logger);

Expand Down
29 changes: 29 additions & 0 deletions GCPCostNotifier/Services/CalculatedDateTimeOffsets.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace GCPCostNotifier.Services;

public class CalculatedDateTimeOffsets
{
/// <summary>
/// 計算に用いる基準日
/// </summary>
public required DateTimeOffset ReferenceDateTimeOffset { get; init; }

/// <summary>
/// 基準日から算出した課金区間の開始日時
/// </summary>
public required DateTimeOffset StartOffsetDateTimeOffset { get; init; }

/// <summary>
/// 基準日から算出した課金区間の終了日時
/// </summary>
public required DateTimeOffset EndOffsetDateTimeOffset { get; init; }

/// <summary>
/// 基準日から算出した課金区間の開始日時のパーティション(課金情報のテーブルの絞り込みに使用する)
/// </summary>
public required DateTimeOffset PartitionStartDateTimeOffset { get; init; }

/// <summary>
/// 基準日から算出した課金区間の終了日時のパーティション(課金情報のテーブルの絞り込みに使用する)
/// </summary>
public required DateTimeOffset PartitionEndDateTimeOffset { get; init; }
}
60 changes: 34 additions & 26 deletions GCPCostNotifier/Services/CostQueryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,20 @@ namespace GCPCostNotifier.Services;
using System.Globalization;
using Google.Cloud.BigQuery.V2;
using Microsoft.Extensions.Logging;
using NodaTime;
using NodaTime.Extensions;

public class CostQueryService(string projectId, string targetTableName, ILogger<CostQueryService> logger)
: ICostQueryService
public class CostQueryService(
string projectId,
string targetTableName,
IDateTimeCalculationService dateTimeCalculationService,
ILogger<CostQueryService> logger
) : ICostQueryService
{
public async Task<IList<CostSummary>> GetYesterdayCostSummaryAsync(DateTimeOffset targetDateTimeOffset,
CancellationToken cancellationToken)
public async Task<IList<CostSummary>> GetYesterdayCostSummaryAsync(
DateTimeOffset targetDateTimeOffset,
CancellationToken cancellationToken
)
{
// 基準日は必ず現在の日付の0時0分0秒にする
var targetZonedDateTime = targetDateTimeOffset.ToZonedDateTime();
var referenceDateTime = targetZonedDateTime.Date.AtStartOfDayInZone(targetZonedDateTime.Zone);

// 開始日はぴったり1日前の日時に指定、終了日は指定された日時にする
var startOffsetDateTime = referenceDateTime.Plus(Duration.Negate(Duration.FromDays(1)));
var endOffsetDateTime = referenceDateTime;

// パーティションの日付は開始日はUTCに変換した日付の0時0分0秒、終了日は指定された日時にする
var partitionStartDateTimeUtc =
startOffsetDateTime.ToOffsetDateTime().InZone(DateTimeZone.Utc).Date.AtStartOfDayInZone(DateTimeZone.Utc);
var partitionEndDateTimeUtc = endOffsetDateTime.ToOffsetDateTime().InZone(DateTimeZone.Utc);
var calculatedDateTimes = dateTimeCalculationService.CalculateDateTimeOffsetsForYesterday(targetDateTimeOffset);

var query =
@$"
Expand All @@ -42,20 +35,35 @@ HAVING SummarizedCost > 0
Log.InitializingBigQueryClient(logger);
using var bqClient = await BigQueryClient.CreateAsync(projectId);

Log.CreatingQueryJob(logger, startOffsetDateTime.ToDateTimeOffset(), endOffsetDateTime.ToDateTimeOffset());
Log.CreatingQueryJob(
logger,
calculatedDateTimes.StartOffsetDateTimeOffset,
calculatedDateTimes.EndOffsetDateTimeOffset
);
var job = await bqClient.CreateQueryJobAsync(
query,
new[]
{
new BigQueryParameter(
"partitionStartDateTime", BigQueryDbType.Timestamp,
partitionStartDateTimeUtc.ToDateTimeOffset()
"partitionStartDateTime",
BigQueryDbType.Timestamp,
calculatedDateTimes.PartitionStartDateTimeOffset
),
new BigQueryParameter(
"partitionEndDateTime",
BigQueryDbType.Timestamp,
calculatedDateTimes.PartitionEndDateTimeOffset
),
new BigQueryParameter("partitionEndDateTime", BigQueryDbType.Timestamp,
partitionEndDateTimeUtc.ToDateTimeOffset()),
new BigQueryParameter("startDateTime", BigQueryDbType.Timestamp,
startOffsetDateTime.ToDateTimeOffset()),
new BigQueryParameter("endDateTime", BigQueryDbType.Timestamp, endOffsetDateTime.ToDateTimeOffset())
new BigQueryParameter(
"startDateTime",
BigQueryDbType.Timestamp,
calculatedDateTimes.StartOffsetDateTimeOffset
),
new BigQueryParameter(
"endDateTime",
BigQueryDbType.Timestamp,
calculatedDateTimes.EndOffsetDateTimeOffset
)
},
cancellationToken: cancellationToken
);
Expand Down
32 changes: 32 additions & 0 deletions GCPCostNotifier/Services/DateTimeCalculationService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace GCPCostNotifier.Services;

using NodaTime;
using NodaTime.Extensions;

public class DateTimeCalculationService : IDateTimeCalculationService
{
public CalculatedDateTimeOffsets CalculateDateTimeOffsetsForYesterday(DateTimeOffset targetDateTimeOffset)
{
// 基準日は必ず現在の日付の0時0分0秒にする
var targetZonedDateTime = targetDateTimeOffset.ToZonedDateTime();
var referenceDateTime = targetZonedDateTime.Date.AtStartOfDayInZone(targetZonedDateTime.Zone);

// 開始日はぴったり1日前の日時に指定、終了日は指定された日時にする
var startOffsetDateTime = referenceDateTime.Plus(Duration.Negate(Duration.FromDays(1)));
var endOffsetDateTime = referenceDateTime;

// パーティションの日付は開始日はUTCに変換した日付の0時0分0秒、終了日は指定された日時にする
var partitionStartDateTimeUtc =
startOffsetDateTime.ToOffsetDateTime().InZone(DateTimeZone.Utc).Date.AtStartOfDayInZone(DateTimeZone.Utc);
var partitionEndDateTimeUtc = endOffsetDateTime.ToOffsetDateTime().InZone(DateTimeZone.Utc);

return new CalculatedDateTimeOffsets
{
ReferenceDateTimeOffset = referenceDateTime.ToDateTimeOffset(),
StartOffsetDateTimeOffset = startOffsetDateTime.ToDateTimeOffset(),
EndOffsetDateTimeOffset = endOffsetDateTime.ToDateTimeOffset(),
PartitionStartDateTimeOffset = partitionStartDateTimeUtc.ToDateTimeOffset(),
PartitionEndDateTimeOffset = partitionEndDateTimeUtc.ToDateTimeOffset()
};
}
}
6 changes: 6 additions & 0 deletions GCPCostNotifier/Services/IDateTimeCalculationService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace GCPCostNotifier.Services;

public interface IDateTimeCalculationService
{
public CalculatedDateTimeOffsets CalculateDateTimeOffsetsForYesterday(DateTimeOffset targetDateTimeOffset);
}
2 changes: 2 additions & 0 deletions GCPCostNotifier/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ public override void ConfigureServices(WebHostBuilderContext context, IServiceCo
?? throw new InvalidOperationException("AppSettings is not configured.");
services
.AddHttpClient()
.AddScoped<IDateTimeCalculationService, DateTimeCalculationService>()
.AddScoped<ICostQueryService, CostQueryService>(v => new CostQueryService(
appSettings.ProjectId,
appSettings.TargetTableName,
v.GetRequiredService<IDateTimeCalculationService>(),
v.GetRequiredService<ILogger<CostQueryService>>()
))
.AddScoped<ISlackNotifier, SlackNotifier>(v =>
Expand Down
17 changes: 14 additions & 3 deletions GCPCostNotifier/YesterdayCostNotifyFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,25 @@
namespace GCPCostNotifier;

using CloudNative.CloudEvents;
using Microsoft.Extensions.Logging;
using Services;

public class YesterdayCostNotifyFunction(ICostQueryService costQueryService, ISlackNotifier slackNotifier) : ICloudEventFunction
public class YesterdayCostNotifyFunction(
ILogger<YesterdayCostNotifyFunction> logger,
ICostQueryService costQueryService,
ISlackNotifier slackNotifier
) : ICloudEventFunction
{
public async Task HandleAsync(CloudEvent cloudEvent, CancellationToken cancellationToken)
{
var tokyoTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo");
var targetDateTimeOffset = TimeZoneInfo.ConvertTime(DateTimeOffset.Now, tokyoTimeZone);
// NOTE: GCPの課金データはロサンゼルス標準時で提供され、かつ、夏時間の影響を受ける
var losAngelesTimeZone = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
var targetDateTimeOffset = TimeZoneInfo.ConvertTime(DateTimeOffset.Now, losAngelesTimeZone);
Log.TriggeredFunction(
logger,
losAngelesTimeZone.Id,
losAngelesTimeZone.IsDaylightSavingTime(targetDateTimeOffset)
);
var results = await costQueryService.GetYesterdayCostSummaryAsync(targetDateTimeOffset, cancellationToken);
await slackNotifier.NotifyDailyResultAsync(results, cancellationToken);
}
Expand Down

0 comments on commit 40b55fc

Please sign in to comment.