Skip to content

Commit 4eb995f

Browse files
committed
added some log in events and api call tracker
1 parent 82a33e9 commit 4eb995f

File tree

10 files changed

+170
-71
lines changed

10 files changed

+170
-71
lines changed
Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,34 @@
11
using DatabaseProjectAPI.DataContext;
22
using DatabaseProjectAPI.Entities;
33

4-
namespace DatabaseProjectAPI.Actions
4+
namespace DatabaseProjectAPI.Actions;
5+
6+
public interface ITrackedStockAction
7+
{
8+
List<TrackedStock> GetTrackedStocks();
9+
void AddTrackedStock(TrackedStock stock);
10+
}
11+
12+
public class TrackedStockAction : ITrackedStockAction
513
{
6-
public interface ITrackedStockAction
14+
private readonly DpapiDbContext _dpapiDbContext;
15+
16+
public TrackedStockAction(DpapiDbContext dpapiDbContext)
717
{
8-
List<TrackedStock> GetTrackedStocks();
9-
void AddTrackedStock(TrackedStock stock);
18+
_dpapiDbContext = dpapiDbContext;
1019
}
11-
12-
public class TrackedStockAction : ITrackedStockAction
20+
public List<TrackedStock> GetTrackedStocks()
1321
{
14-
private readonly DpapiDbContext _dpapiDbContext;
15-
16-
public TrackedStockAction(DpapiDbContext dpapiDbContext)
17-
{
18-
_dpapiDbContext = dpapiDbContext;
19-
}
20-
public List<TrackedStock> GetTrackedStocks()
21-
{
22-
return _dpapiDbContext.TrackedStocks
23-
.OrderBy(s => s.Id)
24-
.ToList();
25-
}
26-
public void AddTrackedStock(TrackedStock stock)
22+
return _dpapiDbContext.TrackedStocks
23+
.OrderBy(s => s.Id)
24+
.ToList();
25+
}
26+
public void AddTrackedStock(TrackedStock stock)
27+
{
28+
if (!_dpapiDbContext.TrackedStocks.Any(s => s.Symbol == stock.Symbol))
2729
{
28-
if (!_dpapiDbContext.TrackedStocks.Any(s => s.Symbol == stock.Symbol))
29-
{
30-
_dpapiDbContext.TrackedStocks.Add(stock);
31-
_dpapiDbContext.SaveChanges();
32-
}
30+
_dpapiDbContext.TrackedStocks.Add(stock);
31+
_dpapiDbContext.SaveChanges();
3332
}
3433
}
3534
}

DatabaseProjectAPI/DataContext/DpapiDbContext.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.EntityFrameworkCore;
22
using DatabaseProjectAPI.Entities;
3+
using DatabaseProjectAPI.Entities.Settings;
34

45
namespace DatabaseProjectAPI.DataContext
56
{
@@ -17,7 +18,7 @@ public interface IDpapiDbContext
1718
DbSet<EventStock> EventStocks { get; set; }
1819
DbSet<EventMutualFund> EventMutualFunds { get; set; }
1920
DbSet<TrackedStock> TrackedStocks { get; set; }
20-
21+
DbSet<ApiCallLog> ApiCallLog { get; set; }
2122
}
2223

2324
public class DpapiDbContext : DbContext, IDpapiDbContext
@@ -38,6 +39,7 @@ public DpapiDbContext(DbContextOptions<DpapiDbContext> options) : base(options)
3839
public DbSet<EventStock> EventStocks { get; set; }
3940
public DbSet<EventMutualFund> EventMutualFunds { get; set; }
4041
public DbSet<TrackedStock> TrackedStocks { get; set; }
42+
public DbSet<ApiCallLog> ApiCallLog { get; set; }
4143
protected override void OnModelCreating(ModelBuilder modelBuilder)
4244
{
4345
base.OnModelCreating(modelBuilder);

DatabaseProjectAPI/DatabaseProjectAPI.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
</ItemGroup>
2020

2121
<ItemGroup>
22-
<Folder Include="Helpers\" />
2322
<Folder Include="DTO\" />
2423
</ItemGroup>
2524

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace DatabaseProjectAPI.Entities.Settings;
2+
3+
[Table("ApiCallLog")]
4+
public class ApiCallLog
5+
{
6+
[Key]
7+
public int Id { get; set; }
8+
[Required]
9+
public DateTime CallDate { get; set; }
10+
[Required]
11+
[MaxLength(50)]
12+
public string? CallType { get; set; }
13+
[Required]
14+
[MaxLength(10)]
15+
public string? Symbol { get; set; }
16+
}

DatabaseProjectAPI/Entities/StockHistory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ public class StockHistory
1515
[Column("closed_value")]
1616
public decimal ClosedValue { get; set; }
1717
[Column("Symbol")]
18-
public string Symbol { get; set; }
18+
public string? Symbol { get; set; }
1919
[ForeignKey("StockId")]
20-
public Stock Stock { get; set; }
20+
public Stock? Stock { get; set; }
2121
}
2222
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using DatabaseProjectAPI.DataContext;
2+
using DatabaseProjectAPI.Entities.Settings;
3+
using Microsoft.EntityFrameworkCore;
4+
5+
namespace DatabaseProjectAPI.Helpers
6+
{
7+
public interface IApiRequestLogger
8+
{
9+
Task<bool> HasMadeApiCallToday(string callType, string symbol);
10+
Task LogApiCall(string callType, string symbol);
11+
}
12+
13+
public class ApiRequestLogger : IApiRequestLogger
14+
{
15+
private readonly DpapiDbContext _dbContext;
16+
17+
public ApiRequestLogger(DpapiDbContext dbContext)
18+
{
19+
_dbContext = dbContext;
20+
}
21+
22+
public async Task<bool> HasMadeApiCallToday(string callType, string symbol)
23+
{
24+
var today = DateTime.UtcNow.Date;
25+
return await _dbContext.ApiCallLog
26+
.AnyAsync(log => log.CallDate == today && log.CallType == callType && log.Symbol == symbol);
27+
}
28+
29+
public async Task LogApiCall(string callType, string symbol)
30+
{
31+
var logEntry = new ApiCallLog
32+
{
33+
CallDate = DateTime.UtcNow.Date,
34+
CallType = callType,
35+
Symbol = symbol
36+
};
37+
38+
_dbContext.ApiCallLog.Add(logEntry);
39+
await _dbContext.SaveChangesAsync();
40+
}
41+
}
42+
}

DatabaseProjectAPI/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using KubsConnect.Settings;
44
using DatabaseProjectAPI.Services;
55
using KubsConnect;
6+
using DatabaseProjectAPI.Helpers;
67

78
var builder = WebApplication.CreateBuilder(args);
89

@@ -37,6 +38,7 @@
3738
builder.Services.AddTransient<IInvestorAccountAction, InvestorAccountAction>();
3839
builder.Services.AddTransient<ITrackedStockAction, TrackedStockAction>();
3940
builder.Services.AddTransient<IStockHistoryAction, StockHistoryAction>();
41+
builder.Services.AddTransient<IApiRequestLogger, ApiRequestLogger>();
4042

4143
// Register background service
4244
builder.Services.AddHostedService<StockQuoteBackgroundService>();
Lines changed: 78 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using DatabaseProjectAPI.DataContext;
22
using DatabaseProjectAPI.Entities;
3+
using DatabaseProjectAPI.Helpers;
34

45
namespace DatabaseProjectAPI.Services
56
{
@@ -16,67 +17,103 @@ public StockQuoteBackgroundService(IServiceProvider serviceProvider, ILogger<Sto
1617

1718
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
1819
{
20+
_logger.LogInformation("StockQuoteBackgroundService started at: {time}", DateTime.UtcNow);
21+
1922
while (!stoppingToken.IsCancellationRequested)
2023
{
2124
var now = DateTime.UtcNow;
2225

23-
if (IsMarketOpenTime(now) || IsMarketCloseTime(now))
26+
using (var scope = _serviceProvider.CreateScope())
2427
{
25-
using (var scope = _serviceProvider.CreateScope())
28+
var dbContext = scope.ServiceProvider.GetRequiredService<DpapiDbContext>();
29+
var apiRequestLogger = scope.ServiceProvider.GetRequiredService<IApiRequestLogger>();
30+
31+
// Check if API call has already been made today for market open or close
32+
if (IsMarketOpenTime(now) && !await apiRequestLogger.HasMadeApiCallToday("MarketOpen", "AAPL"))
33+
{
34+
await FetchAndSaveStockData(dbContext, apiRequestLogger, "MarketOpen", "AAPL");
35+
}
36+
else if (IsMarketCloseTime(now) && !await apiRequestLogger.HasMadeApiCallToday("MarketClose", "AAPL"))
2637
{
27-
var stockService = scope.ServiceProvider.GetRequiredService<IAlphaVantageService>();
28-
var dbContext = scope.ServiceProvider.GetRequiredService<DpapiDbContext>();
29-
30-
try
31-
{
32-
var stockQuote = await stockService.GetStockQuote("AAPL");
33-
34-
var stock = await dbContext.Stocks
35-
.FirstOrDefaultAsync(s => s.Symbol == stockQuote.Symbol, stoppingToken);
36-
37-
if (stock == null)
38-
{
39-
_logger.LogWarning("Stock not found in the database. Symbol: {Symbol}", stockQuote.Symbol);
40-
continue;
41-
}
42-
43-
var stockHistory = new StockHistory
44-
{
45-
StockId = stock.StockId,
46-
Timestamp = stockQuote.LatestTradingDay,
47-
OpenedValue = stockQuote.Open,
48-
ClosedValue = stockQuote.Price
49-
};
50-
51-
52-
dbContext.StockHistories.Add(stockHistory);
53-
await dbContext.SaveChangesAsync(stoppingToken);
54-
55-
_logger.LogInformation("Stock history saved successfully for {Symbol} at {Timestamp}", stock.Symbol, stockHistory.Timestamp);
56-
}
57-
catch (Exception ex)
58-
{
59-
_logger.LogError(ex, "Error occurred while fetching and saving stock history data.");
60-
}
38+
await FetchAndSaveStockData(dbContext, apiRequestLogger, "MarketClose", "AAPL");
6139
}
6240
}
6341

64-
await Task.Delay(TimeSpan.FromMinutes(60), stoppingToken); // Check every hour
42+
await Task.Delay(TimeSpan.FromMinutes(60), stoppingToken); // Delay for 1 hour
43+
}
44+
}
45+
private async Task FetchAndSaveStockData(DpapiDbContext dbContext, IApiRequestLogger apiRequestLogger, string callType, string symbol)
46+
{
47+
using (var scope = _serviceProvider.CreateScope())
48+
{
49+
var stockService = scope.ServiceProvider.GetRequiredService<IAlphaVantageService>();
50+
51+
try
52+
{
53+
var stockQuote = await stockService.GetStockQuote(symbol);
54+
55+
// Find stock by symbol
56+
var stock = await dbContext.Stocks.FirstOrDefaultAsync(s => s.Symbol == stockQuote.Symbol);
57+
58+
if (stock == null)
59+
{
60+
_logger.LogWarning("Stock not found in the database. Symbol: {Symbol}", stockQuote.Symbol);
61+
return;
62+
}
63+
64+
var stockHistory = new StockHistory
65+
{
66+
StockId = stock.StockId,
67+
Timestamp = stockQuote.LatestTradingDay,
68+
OpenedValue = stockQuote.Open,
69+
ClosedValue = stockQuote.Price
70+
};
71+
72+
dbContext.StockHistories.Add(stockHistory);
73+
await dbContext.SaveChangesAsync();
74+
75+
// Log that an API call was made
76+
await apiRequestLogger.LogApiCall(callType, symbol);
77+
78+
_logger.LogInformation("Stock history saved successfully for {Symbol} at {Timestamp}", stock.Symbol, stockHistory.Timestamp);
79+
}
80+
catch (Exception ex)
81+
{
82+
_logger.LogError(ex, "Error occurred while fetching and saving stock history data.");
83+
}
6584
}
6685
}
86+
6787

6888
private bool IsMarketOpenTime(DateTime currentTime)
6989
{
70-
TimeZoneInfo est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
71-
var marketOpenTime = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, 9, 30, 0), est);
90+
TimeZoneInfo easternTime = GetEasternTimeZone();
91+
var marketOpenTime = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, 9, 30, 0), easternTime);
7292
return currentTime >= marketOpenTime && currentTime < marketOpenTime.AddMinutes(1); // Within 1 minute of market opening
7393
}
7494

7595
private bool IsMarketCloseTime(DateTime currentTime)
7696
{
77-
TimeZoneInfo est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
78-
var marketCloseTime = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, 16, 0, 0), est);
97+
TimeZoneInfo easternTime = GetEasternTimeZone();
98+
var marketCloseTime = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, 16, 0, 0), easternTime);
7999
return currentTime >= marketCloseTime && currentTime < marketCloseTime.AddMinutes(1); // Within 1 minute of market closing
80100
}
101+
private TimeZoneInfo GetEasternTimeZone()
102+
{
103+
try
104+
{
105+
return TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
106+
}
107+
catch (TimeZoneNotFoundException)
108+
{
109+
return TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
110+
}
111+
catch (InvalidTimeZoneException)
112+
{
113+
throw new Exception("Unable to determine the Eastern Time zone.");
114+
}
115+
}
116+
81117
}
118+
82119
}

DatabaseProjectAPI/appsettings.Development.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"Logging": {
33
"LogLevel": {
44
"Default": "Information",
5-
"Microsoft.AspNetCore": "Warning"
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
67
}
78
}
89
}

DatabaseProjectAPI/appsettings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"Logging": {
1212
"LogLevel": {
1313
"Default": "Information",
14-
"Microsoft.AspNetCore": "Warning"
14+
"Microsoft": "Warning",
15+
"Microsoft.Hosting.Lifetime": "Information"
1516
}
1617
},
1718
"AllowedHosts": "*"

0 commit comments

Comments
 (0)