···205205 close(done)
206206 }()
207207208208+ // recipes can take several minutes to complete.
209209+ ctx, cancel = context.WithTimeout(context.Background(), 3*time.Minute)
210210+ defer cancel()
208211 // Wait for all recipe generation goroutines to complete
209212 slog.Info("Waiting for recipe generation goroutines to complete")
210213
+35-22
internal/recipes/server.go
···850850 return
851851 }
852852853853- if startTime, err := time.Parse(time.RFC3339Nano, startArg); err == nil {
854854- if time.Since(startTime) > time.Minute*10 {
855855- p, err := s.ParamsFromCache(ctx, hashParam)
856856- if err != nil {
857857- slog.ErrorContext(ctx, "failed to load params for hash", "hash", hashParam, "error", err)
858858- http.Error(w, "recipe not found or expired", http.StatusNotFound)
859859- return
860860- }
853853+ startTime, err := time.Parse(time.RFC3339Nano, startArg)
854854+ if err != nil {
855855+ slog.ErrorContext(ctx, "failed to parse start time", "time", startArg, "error", err)
856856+ redirectToHash(w, r, hashParam, true /*useStart*/)
857857+ return
858858+ }
859859+860860+ if time.Since(startTime) < time.Minute*10 {
861861+ s.Spin(w, r)
862862+ return
863863+ }
864864+ slog.WarnContext(ctx, "rekicking generation", "time", startArg, "hash", hashParam)
865865+866866+ p, err := s.ParamsFromCache(ctx, hashParam)
867867+ if err != nil {
868868+ slog.ErrorContext(ctx, "failed to load params for hash", "hash", hashParam, "error", err)
869869+ http.Error(w, "recipe not found or expired", http.StatusNotFound)
870870+ return
871871+ }
861872862862- currentUser, err := s.storage.FromRequest(ctx, r, s.clerk) // just for logging purposes in kickgeneration. We could do this in the generateion function instead to avoid the extra call on every not found.
863863- if err != nil {
864864- if !errors.Is(err, auth.ErrNoSession) {
865865- slog.ErrorContext(ctx, "failed to get clerk user ID", "error", err)
866866- http.Error(w, "unable to load account", http.StatusInternalServerError)
867867- return
868868- }
869869- http.Redirect(w, r, "/", http.StatusSeeOther)
870870- return
871871- }
872872- s.kickgeneration(ctx, p, currentUser)
873873- redirectToHash(w, r, p.Hash(), true /*useStart*/)
873873+ // this could fail becasuse clerk isn't refreshing?
874874+ currentUser, err := s.storage.FromRequest(ctx, r, s.clerk) // just for logging purposes in kickgeneration. We could do this in the generateion function instead to avoid the extra call on every not found.
875875+ if err != nil {
876876+ if !errors.Is(err, auth.ErrNoSession) {
877877+ slog.ErrorContext(ctx, "failed to get clerk user ID", "error", err)
878878+ http.Error(w, "unable to load account", http.StatusInternalServerError)
874879 return
875880 }
881881+ slog.WarnContext(ctx, "no valid session found from spin page.", "hash", hashParam)
882882+ http.Redirect(w, r, "/", http.StatusSeeOther)
883883+ return
876884 }
877877- s.Spin(w, r)
885885+ s.kickgeneration(ctx, p, currentUser)
886886+ redirectToHash(w, r, p.Hash(), true /*useStart*/)
878887}
879888880889func (s *server) handleRecipes(w http.ResponseWriter, r *http.Request) {
···10211030 return r.Title, cooked[r.Hash].Cooked
10221031 })
1023103210241024- slog.InfoContext(ctx, "generating cached recipes", "params", p.String(), "hash", hash)
10331033+ slog.InfoContext(ctx, "generating cached recipes", "params", p.String(), "hash", hash, "user_id", currentUser.ID)
10251034 shoppingList, err := s.generator.GenerateRecipes(ctx, p)
10261035 if err != nil {
10271036 slog.ErrorContext(ctx, "generate error", "error", err)
···10401049func (s *server) Spin(w http.ResponseWriter, r *http.Request) {
10411050 w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate")
10421051 ctx := r.Context()
10521052+ _, err := s.clerk.GetUserIDFromRequest(r)
10531053+ signedIn := !errors.Is(err, auth.ErrNoSession)
10431054 spinnerData := struct {
10441055 ClarityScript template.HTML
10451056 GoogleTagScript template.HTML
10461057 Style seasons.Style
10581058+ ServerSignedIn bool
10471059 RefreshInterval string // seconds
10481060 }{
10491061 ClarityScript: templates.ClarityScript(ctx),
10501062 GoogleTagScript: templates.GoogleTagScript(),
10511063 Style: seasons.GetCurrentStyle(),
10641064+ ServerSignedIn: signedIn,
10521065 RefreshInterval: "10", // seconds
10531066 }
10541067