Skip to content

Commit c59051f

Browse files
committed
refactor(feeds): remove feeds after 3 failed attempts
We have a bunch of feeds in our system that are failing in a loop. Previously we did not notify the user when there was a failure, we just logged it internally. With this change, we will prepend errors to the email message body. Further, if the feeds errors and doesn't return any feed items, we increment a counter. 3 failed attempts and we remove the post and notify the user.
1 parent 7372600 commit c59051f

File tree

2 files changed

+74
-11
lines changed

2 files changed

+74
-11
lines changed

db/db.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type User struct {
3232
type PostData struct {
3333
ImgPath string `json:"img_path"`
3434
LastDigest *time.Time `json:"last_digest"`
35+
Attempts int `json:"attempts"`
3536
}
3637

3738
// Make the Attrs struct implement the driver.Valuer interface. This method

feeds/cron.go

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,25 +175,77 @@ func (f *Fetcher) RunPost(logger *slog.Logger, user *db.User, post *db.Post) err
175175
urls = append(urls, url)
176176
}
177177

178-
msgBody, err := f.FetchAll(logger, urls, parsed.InlineContent, user.Name, post)
178+
now := time.Now().UTC()
179+
if post.ExpiresAt == nil {
180+
expiresAt := time.Now().AddDate(0, 6, 0)
181+
post.ExpiresAt = &expiresAt
182+
}
183+
post.Data.LastDigest = &now
184+
_, err = f.db.UpdatePost(post)
179185
if err != nil {
180186
return err
181187
}
182188

183189
subject := fmt.Sprintf("%s feed digest", post.Title)
184-
err = f.SendEmail(logger, user.Name, parsed.Email, subject, msgBody)
190+
191+
msgBody, err := f.FetchAll(logger, urls, parsed.InlineContent, user.Name, post)
185192
if err != nil {
186-
return err
193+
errForUser := err
194+
195+
// we don't want to increment in this case
196+
if errors.Is(errForUser, ErrNoRecentArticles) {
197+
return nil
198+
}
199+
200+
post.Data.Attempts += 1
201+
logger.Error("could not fetch urls", "err", err, "attempts", post.Data.Attempts)
202+
203+
errBody := fmt.Sprintf(`There was an error attempting to fetch your feeds (%d) times. After (3) attempts we remove the file from our system. Please check all the URLs and re-upload.
204+
Also, we have centralized logs in our pico.sh TUI that will display realtime feed errors so you can debug.
205+
206+
207+
%s
208+
209+
210+
%s`, post.Data.Attempts, errForUser.Error(), post.Text)
211+
err = f.SendEmail(
212+
logger, user.Name,
213+
parsed.Email,
214+
subject,
215+
&MsgBody{Html: strings.ReplaceAll(errBody, "\n", "<br />"), Text: errBody},
216+
)
217+
if err != nil {
218+
return err
219+
}
220+
221+
if post.Data.Attempts >= 3 {
222+
err = f.db.RemovePosts([]string{post.ID})
223+
if err != nil {
224+
return err
225+
}
226+
} else {
227+
_, err = f.db.UpdatePost(post)
228+
if err != nil {
229+
return err
230+
}
231+
}
232+
return errForUser
233+
} else {
234+
post.Data.Attempts = 0
235+
_, err := f.db.UpdatePost(post)
236+
if err != nil {
237+
return err
238+
}
187239
}
188240

189-
now := time.Now().UTC()
190-
if post.ExpiresAt == nil {
191-
expiresAt := time.Now().AddDate(0, 6, 0)
192-
post.ExpiresAt = &expiresAt
241+
if msgBody != nil {
242+
err = f.SendEmail(logger, user.Name, parsed.Email, subject, msgBody)
243+
if err != nil {
244+
return err
245+
}
193246
}
194-
post.Data.LastDigest = &now
195-
_, err = f.db.UpdatePost(post)
196-
return err
247+
248+
return nil
197249
}
198250

199251
func (f *Fetcher) RunUser(user *db.User) error {
@@ -353,12 +405,14 @@ func (f *Fetcher) FetchAll(logger *slog.Logger, urls []string, inlineContent boo
353405
return nil, err
354406
}
355407

408+
var allErrors error
356409
for _, url := range urls {
357410
feedTmpl, err := f.Fetch(logger, fp, url, username, feedItems)
358411
if err != nil {
359412
if errors.Is(err, ErrNoRecentArticles) {
360413
logger.Info("no recent articles", "err", err)
361414
} else {
415+
allErrors = errors.Join(allErrors, fmt.Errorf("%s: %w", url, err))
362416
logger.Error("fetch error", "err", err)
363417
}
364418
continue
@@ -367,7 +421,10 @@ func (f *Fetcher) FetchAll(logger *slog.Logger, urls []string, inlineContent boo
367421
}
368422

369423
if len(feeds.Feeds) == 0 {
370-
return nil, fmt.Errorf("(%s) %w, skipping email", username, ErrNoRecentArticles)
424+
if allErrors != nil {
425+
return nil, allErrors
426+
}
427+
return nil, fmt.Errorf("%w, skipping email", ErrNoRecentArticles)
371428
}
372429

373430
fdi := []*db.FeedItem{}
@@ -401,6 +458,11 @@ func (f *Fetcher) FetchAll(logger *slog.Logger, urls []string, inlineContent boo
401458
return nil, err
402459
}
403460

461+
if allErrors != nil {
462+
text = fmt.Sprintf("> %s\n\n%s", allErrors, text)
463+
html = fmt.Sprintf("<blockquote>%s</blockquote><br /><br/>%s", allErrors, html)
464+
}
465+
404466
return &MsgBody{
405467
Text: text,
406468
Html: html,

0 commit comments

Comments
 (0)