mirror of
https://github.com/Xevion/banner.git
synced 2025-12-09 08:06:41 -06:00
feat: proper context handeling, graceful cancellation & shutdown
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"banner/internal/models"
|
||||
"banner/internal/utils"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -76,7 +77,14 @@ func (a *API) DoRequest(req *http.Request) (*http.Response, error) {
|
||||
Str("content-type", req.Header.Get("Content-Type")).
|
||||
Msg("Request")
|
||||
|
||||
res, err := a.config.Client.Do(req)
|
||||
// Create a timeout context for this specific request
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Clone the request with the timeout context
|
||||
reqWithTimeout := req.Clone(ctx)
|
||||
|
||||
res, err := a.config.Client.Do(reqWithTimeout)
|
||||
|
||||
if err != nil {
|
||||
log.Err(err).Stack().Str("method", req.Method).Msg("Request Failed")
|
||||
@@ -614,8 +622,12 @@ func (a *API) ResetDataForm() {
|
||||
// GetCourse retrieves the course information.
|
||||
// This course does not retrieve directly from the API, but rather uses scraped data stored in Redis.
|
||||
func (a *API) GetCourse(crn string) (*models.Course, error) {
|
||||
// Create a timeout context for Redis operations
|
||||
ctx, cancel := context.WithTimeout(a.config.Ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Retrieve raw data
|
||||
result, err := a.config.KV.Get(a.config.Ctx, fmt.Sprintf("class:%s", crn)).Result()
|
||||
result, err := a.config.KV.Get(ctx, fmt.Sprintf("class:%s", crn)).Result()
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
return nil, fmt.Errorf("course not found: %w", err)
|
||||
|
||||
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"banner/internal/models"
|
||||
"banner/internal/utils"
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
@@ -72,8 +73,12 @@ func (a *API) GetExpiredSubjects() ([]string, error) {
|
||||
term := utils.Default(time.Now()).ToString()
|
||||
subjects := make([]string, 0)
|
||||
|
||||
// Create a timeout context for Redis operations
|
||||
ctx, cancel := context.WithTimeout(a.config.Ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Get all subjects
|
||||
values, err := a.config.KV.MGet(a.config.Ctx, lo.Map(AllMajors, func(major string, _ int) string {
|
||||
values, err := a.config.KV.MGet(ctx, lo.Map(AllMajors, func(major string, _ int) string {
|
||||
return fmt.Sprintf("scraped:%s:%s", major, term)
|
||||
})...).Result()
|
||||
if err != nil {
|
||||
@@ -161,7 +166,12 @@ func (a *API) ScrapeMajor(subject string) error {
|
||||
if totalClassCount == 0 {
|
||||
totalClassCount = -1
|
||||
}
|
||||
err := a.config.KV.Set(a.config.Ctx, fmt.Sprintf("scraped:%s:%s", subject, term), totalClassCount, scrapeExpiry).Err()
|
||||
|
||||
// Create a timeout context for Redis operations
|
||||
ctx, cancel := context.WithTimeout(a.config.Ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
err := a.config.KV.Set(ctx, fmt.Sprintf("scraped:%s:%s", subject, term), totalClassCount, scrapeExpiry).Err()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to mark major as scraped")
|
||||
}
|
||||
@@ -214,7 +224,11 @@ func (a *API) CalculateExpiry(term string, count int, priority bool) time.Durati
|
||||
// IntakeCourse stores a course in Redis.
|
||||
// This function is mostly a stub for now, but will be used to handle change identification, notifications, and SQLite upserts in the future.
|
||||
func (a *API) IntakeCourse(course models.Course) error {
|
||||
err := a.config.KV.Set(a.config.Ctx, fmt.Sprintf("class:%s", course.CourseReferenceNumber), course, 0).Err()
|
||||
// Create a timeout context for Redis operations
|
||||
ctx, cancel := context.WithTimeout(a.config.Ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
err := a.config.KV.Set(ctx, fmt.Sprintf("class:%s", course.CourseReferenceNumber), course, 0).Err()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to store class in Redis: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user