···188188 use _ <- result.try(
189189 database.delete_subscription(backend.database, user, feed)
190190 |> result.map_error(fn(error) {
191191- log(woof.Error, "Failed to add user to database", [
191191+ log(woof.Error, "Failed to delete subscription in database", [
192192 woof.str("user-email", user.email),
193193 woof.str("user-id", user.id |> uuid.to_string()),
194194+ woof.str("feed-url", feed.link |> uri.to_string()),
195195+ woof.str("feed-id", feed.id |> uuid.to_string()),
194196 woof.str("details", string.inspect(error)),
195197 ])
196198 }),
···499501 user: user.User,
500502 feed: rss.Location,
501503) -> actor.Next(State, Message) {
502502- // - notify sender
503503- sender.remove_subscription(state.names.sender_manager, user, feed)
504504-505505- use subscribers <- try_twice(
506506- fn() { database.subscription_count(feed, state.database) },
507507- otherwise: log_and_stop(
504504+ // we failed to get the subscriber count
505505+ let subscriber_count_failed = fn(error) {
506506+ woof.log(
508507 state.logger,
508508+ woof.Error,
509509 "Failed get subscriber count from database",
510510 [
511511- woof.str("feed", feed.link |> uri.to_string()),
511511+ woof.str("feed-url", feed.link |> uri.to_string()),
512512+ woof.str("feed-id", feed.id |> uuid.to_string()),
513513+ woof.str("details", string.inspect(error)),
512514 ],
513513- ),
514514- )
515515+ )
516516+ actor.stop_abnormal("Failed get subscriber count from database")
517517+ }
515518516516- case subscribers {
517517- // - if noone is subscribed
518518- 0 -> {
519519- // - stop fetcher
520520- fetcher.stop_for(state.names.fetcher_manager, feed)
521521- // - remove feed from database
519519+ // noone is subscribed anymore, so we remove this feed from the database
520520+ // and stop the fetcher for it
521521+ let noone_subscribed = fn() {
522522+ // - stop fetcher
523523+ fetcher.stop_for(state.names.fetcher_manager, feed)
522524523523- case database.delete_feed(state.database, feed) {
524524- Ok(_) -> actor.continue(state)
525525- Error(error) -> {
526526- woof.log(
527527- state.logger,
528528- woof.Error,
529529- "Failed to delete feed from database",
530530- [
531531- woof.str("feed-url", feed.link |> uri.to_string()),
532532- woof.str("feed-id", feed.id |> uuid.to_string()),
533533- woof.str("details", string.inspect(error)),
534534- ],
535535- )
536536- actor.stop_abnormal("Failed to delete feed from database")
537537- }
525525+ // - remove feed from database
526526+ case database.delete_feed(state.database, feed) {
527527+ Ok(_) -> actor.continue(state)
528528+ Error(error) -> {
529529+ woof.log(
530530+ state.logger,
531531+ woof.Error,
532532+ "Failed to delete feed from database",
533533+ [
534534+ woof.str("feed-url", feed.link |> uri.to_string()),
535535+ woof.str("feed-id", feed.id |> uuid.to_string()),
536536+ woof.str("details", string.inspect(error)),
537537+ ],
538538+ )
539539+ actor.stop_abnormal("Failed to delete feed from database")
538540 }
539541 }
540540- _ -> actor.continue(state)
541542 }
542542-}
543543544544-// helpers ----------------------------------------------------------------------
544544+ // - notify sender, through manager
545545+ sender.remove_subscription(state.names.sender_manager, user, feed)
545546546546-/// returns a function that logs an error
547547-/// to the supplied logger with the supplied message
548548-/// and then returns `actor.stop_abnormal` with that same message
549549-///
550550-fn log_and_stop(
551551- logger logger: woof.Logger,
552552- message message: String,
553553- fields fields: List(#(String, _)),
554554-) -> fn(a) -> actor.Next(b, c) {
555555- fn(error) {
556556- woof.log(logger, woof.Error, message, [
557557- woof.str("details", string.inspect(error)),
558558- ..fields
559559- ])
560560- actor.stop_abnormal(message)
561561- }
562562-}
563563-564564-fn try_twice(
565565- try try: fn() -> Result(a, b),
566566- otherwise otherwise: fn(b) -> c,
567567- continue continue: fn(a) -> c,
568568-) -> c {
569569- case try() {
570570- Ok(value) -> continue(value)
571571- Error(_) ->
572572- case try() {
573573- Ok(value) -> continue(value)
574574- Error(error) -> otherwise(error)
575575- }
547547+ // check subscription count for this feed
548548+ case database.subscription_count(feed, state.database) {
549549+ // remove it when noone is subscribed anymore
550550+ Ok(0) -> noone_subscribed()
551551+ // or continue otherwise
552552+ Ok(_) -> actor.continue(state)
553553+ // and stop stop abnormally when checking returned an error
554554+ Error(error) -> subscriber_count_failed(error)
576555 }
577556}
+62-57
src/eater/fetcher.gleam
···400400401401 // if we've failed to fetch the feed too many times
402402 // stop fetching for this feed, until it gets started again
403403- case state.feed |> rss.is_fetching_paused() {
404404- True -> failed_too_often(state)
405405- False -> {
406406- let reset_timer_and_continue = fn(state: State) {
407407- // cancel old timer in case we received another CheckFeeds message that wasnt sent by the timer
408408- // from the Ui for example
409409- process.cancel_timer(state.fetch_timer)
403403+ use <- bool.lazy_guard(
404404+ when: rss.is_fetching_paused(state.feed),
405405+ return: fn() { failed_too_often(state) },
406406+ )
410407411411- // update the `next_check` timestamp in the `rss.Location`
412412- let feed = rss.next_check_in(state.feed, duration_between_checks())
408408+ // only actually check the feed if there are people subscribed to it
409409+ case pubsub.subscriber_count_feed(state.feed, state.registry) {
410410+ [] -> {
411411+ log(woof.Warning, "Skipping", [
412412+ woof.str("feed-url", state.feed.link |> uri.to_string()),
413413+ woof.str("feed-id", state.feed.id |> uuid.to_string()),
414414+ woof.str("reason", "No sender is subscribed"),
415415+ ])
416416+ reset_timer_and_continue(state)
417417+ }
413418414414- // and save it to the database
415415- case database.update_feed_next_check(state.database, feed) {
416416- Error(_) ->
417417- actor.stop_abnormal(
418418- "Failed to persist new next_check for "
419419- <> state.feed.id |> uuid.to_string()
420420- <> " "
421421- <> state.feed.link |> uri.to_string(),
422422- )
423423- // we managed to delete it
424424- // lets notify the other
425425- Ok(_) -> {
426426- // check again after interval has elapsed
427427- let fetch_timer =
428428- process.send_after(
429429- state.self,
430430- duration_between_checks() |> duration.to_milliseconds(),
431431- CheckFeed,
432432- )
419419+ [_, ..] ->
420420+ case handle_feed_fetching(state) {
421421+ Ok(state) -> reset_timer_and_continue(state)
422422+ Error(stop) -> stop
423423+ }
424424+ }
425425+ }
426426+ }
427427+}
428428+429429+/// resets the fetch timer, updates the next_feed_check in the database
430430+/// and `actor.continue(state)`'s
431431+///
432432+/// if the database write fails it will stop abnormally
433433+///
434434+fn reset_timer_and_continue(state: State) {
435435+ // cancel old timer in case we received another CheckFeeds message that wasnt sent by the timer
436436+ // from the Ui for example
437437+ process.cancel_timer(state.fetch_timer)
433438434434- log(woof.Info, "Next check is at", [
435435- woof.str(
436436- "timestamp",
437437- feed.next_check
438438- |> timestamp.to_rfc3339(calendar.local_offset()),
439439- ),
440440- ])
439439+ // update the `next_check` timestamp in the `rss.Location`
440440+ let feed = rss.next_check_in(state.feed, duration_between_checks())
441441442442- actor.continue(State(..state, fetch_timer:, feed:))
443443- }
444444- }
445445- }
442442+ // and save it to the database
443443+ case database.update_feed_next_check(state.database, feed) {
444444+ Error(_) ->
445445+ actor.stop_abnormal(
446446+ "Failed to persist new next_check for "
447447+ <> state.feed.id |> uuid.to_string()
448448+ <> " "
449449+ <> state.feed.link |> uri.to_string(),
450450+ )
451451+ // we managed to delete it
452452+ // lets notify the other
453453+ Ok(_) -> {
454454+ // check again after interval has elapsed
455455+ let fetch_timer =
456456+ process.send_after(
457457+ state.self,
458458+ duration_between_checks() |> duration.to_milliseconds(),
459459+ CheckFeed,
460460+ )
446461447447- // only actually check the feed if there are people subscribed to it
448448- case pubsub.subscriber_count_feed(state.feed, state.registry) {
449449- [] -> {
450450- log(woof.Warning, "Skipping", [
451451- woof.str("feed-url", state.feed.link |> uri.to_string()),
452452- woof.str("feed-id", state.feed.id |> uuid.to_string()),
453453- woof.str("reason", "No sender is subscribed"),
454454- ])
455455- reset_timer_and_continue(state)
456456- }
462462+ log(woof.Info, "Next check is at", [
463463+ woof.str(
464464+ "timestamp",
465465+ feed.next_check
466466+ |> timestamp.to_rfc3339(calendar.local_offset()),
467467+ ),
468468+ ])
457469458458- [_, ..] ->
459459- case handle_feed_fetching(state) {
460460- Ok(state) -> reset_timer_and_continue(state)
461461- Error(stop) -> stop
462462- }
463463- }
464464- }
465465- }
470470+ actor.continue(State(..state, fetch_timer:, feed:))
466471 }
467472 }
468473}