From 39072600d3ebcdd47569524103607cacea18ffc4 Mon Sep 17 00:00:00 2001 From: rook1e Date: Mon, 18 Mar 2024 18:17:43 +0800 Subject: [PATCH] refactor: derive context from user's request --- api/api.go | 4 ++++ api/feed.go | 14 +++++++------- api/group.go | 8 ++++---- api/item.go | 10 +++++----- pkg/httpx/httpx.go | 2 +- server/feed.go | 28 ++++++++++++++-------------- server/group.go | 9 +++++---- server/item.go | 12 +++++++----- service/pull/handle.go | 2 ++ service/pull/pull.go | 14 +++----------- 10 files changed, 52 insertions(+), 51 deletions(-) diff --git a/api/api.go b/api/api.go index 2b7ebba..df43af4 100644 --- a/api/api.go +++ b/api/api.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "strings" + "time" "github.com/0x2e/fusion/conf" "github.com/0x2e/fusion/frontend" @@ -67,6 +68,9 @@ func Run() { return nil }, })) + r.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{ + Timeout: 30 * time.Second, + })) r.Use(session.Middleware(sessions.NewCookieStore([]byte("fusion")))) r.Pre(middleware.RemoveTrailingSlash()) diff --git a/api/feed.go b/api/feed.go index f0e758a..4df9f51 100644 --- a/api/feed.go +++ b/api/feed.go @@ -19,7 +19,7 @@ func newFeedAPI(srv *server.Feed) *feedAPI { } func (f feedAPI) All(c echo.Context) error { - resp, err := f.srv.All() + resp, err := f.srv.All(c.Request().Context()) if err != nil { return err } @@ -33,7 +33,7 @@ func (f feedAPI) Get(c echo.Context) error { return err } - resp, err := f.srv.Get(&req) + resp, err := f.srv.Get(c.Request().Context(), &req) if err != nil { return err } @@ -47,7 +47,7 @@ func (f feedAPI) Create(c echo.Context) error { return err } - if err := f.srv.Create(&req); err != nil { + if err := f.srv.Create(c.Request().Context(), &req); err != nil { return err } @@ -60,7 +60,7 @@ func (f feedAPI) CheckValidity(c echo.Context) error { return err } - resp, err := f.srv.CheckValidity(&req) + resp, err := f.srv.CheckValidity(c.Request().Context(), &req) if err != nil { return err } @@ -74,7 +74,7 @@ func (f feedAPI) Update(c echo.Context) error { return err } - err := f.srv.Update(&req) + err := f.srv.Update(c.Request().Context(), &req) if err != nil { return err } @@ -88,7 +88,7 @@ func (f feedAPI) Delete(c echo.Context) error { return err } - if err := f.srv.Delete(&req); err != nil { + if err := f.srv.Delete(c.Request().Context(), &req); err != nil { return err } @@ -101,7 +101,7 @@ func (f feedAPI) Refresh(c echo.Context) error { return err } - if err := f.srv.Refresh(&req); err != nil { + if err := f.srv.Refresh(c.Request().Context(), &req); err != nil { return err } diff --git a/api/group.go b/api/group.go index 8759a0a..b67af19 100644 --- a/api/group.go +++ b/api/group.go @@ -19,7 +19,7 @@ func newGroupAPI(srv *server.Group) *groupAPI { } func (f groupAPI) All(c echo.Context) error { - resp, err := f.srv.All() + resp, err := f.srv.All(c.Request().Context()) if err != nil { return err } @@ -33,7 +33,7 @@ func (f groupAPI) Create(c echo.Context) error { return err } - if err := f.srv.Create(&req); err != nil { + if err := f.srv.Create(c.Request().Context(), &req); err != nil { return err } @@ -46,7 +46,7 @@ func (f groupAPI) Update(c echo.Context) error { return err } - err := f.srv.Update(&req) + err := f.srv.Update(c.Request().Context(), &req) if err != nil { return err } @@ -60,7 +60,7 @@ func (f groupAPI) Delete(c echo.Context) error { return err } - if err := f.srv.Delete(&req); err != nil { + if err := f.srv.Delete(c.Request().Context(), &req); err != nil { return err } diff --git a/api/item.go b/api/item.go index 85430fa..15564a4 100644 --- a/api/item.go +++ b/api/item.go @@ -24,7 +24,7 @@ func (i itemAPI) List(c echo.Context) error { return err } - resp, err := i.srv.List(&req) + resp, err := i.srv.List(c.Request().Context(), &req) if err != nil { return err } @@ -38,7 +38,7 @@ func (i itemAPI) Get(c echo.Context) error { return err } - resp, err := i.srv.Get(&req) + resp, err := i.srv.Get(c.Request().Context(), &req) if err != nil { return err } @@ -52,7 +52,7 @@ func (i itemAPI) Delete(c echo.Context) error { return err } - if err := i.srv.Delete(&req); err != nil { + if err := i.srv.Delete(c.Request().Context(), &req); err != nil { return err } @@ -65,7 +65,7 @@ func (i itemAPI) UpdateUnread(c echo.Context) error { return err } - if err := i.srv.UpdateUnread(&req); err != nil { + if err := i.srv.UpdateUnread(c.Request().Context(), &req); err != nil { return err } @@ -78,7 +78,7 @@ func (i itemAPI) UpdateBookmark(c echo.Context) error { return err } - if err := i.srv.UpdateBookmark(&req); err != nil { + if err := i.srv.UpdateBookmark(c.Request().Context(), &req); err != nil { return err } diff --git a/pkg/httpx/httpx.go b/pkg/httpx/httpx.go index e6ba1f8..51a8c46 100644 --- a/pkg/httpx/httpx.go +++ b/pkg/httpx/httpx.go @@ -42,6 +42,6 @@ func NewSafeClient() *http.Client { } return &http.Client{ Transport: safeTransport, - Timeout: 10 * time.Second, + Timeout: 1 * time.Minute, // fallback } } diff --git a/server/feed.go b/server/feed.go index f6a02e9..20b04b5 100644 --- a/server/feed.go +++ b/server/feed.go @@ -6,7 +6,6 @@ import ( "net/http" "net/url" "sync" - "time" "github.com/0x2e/fusion/model" "github.com/0x2e/fusion/repo" @@ -40,7 +39,7 @@ func NewFeed(feedRepo FeedRepo, itemRepo ItemInFeedRepo) *Feed { } } -func (f Feed) All() (*RespFeedAll, error) { +func (f Feed) All(ctx context.Context) (*RespFeedAll, error) { data, err := f.feedRepo.All() if err != nil { return nil, err @@ -63,7 +62,7 @@ func (f Feed) All() (*RespFeedAll, error) { }, nil } -func (f Feed) Get(req *ReqFeedGet) (*RespFeedGet, error) { +func (f Feed) Get(ctx context.Context, req *ReqFeedGet) (*RespFeedGet, error) { data, err := f.feedRepo.Get(req.ID) if err != nil { return nil, err @@ -79,7 +78,7 @@ func (f Feed) Get(req *ReqFeedGet) (*RespFeedGet, error) { }, nil } -func (f Feed) Create(req *ReqFeedCreate) error { +func (f Feed) Create(ctx context.Context, req *ReqFeedCreate) error { feeds := make([]*model.Feed, 0, len(req.Feeds)) for _, r := range req.Feeds { feeds = append(feeds, &model.Feed{ @@ -109,7 +108,9 @@ func (f Feed) Create(req *ReqFeedCreate) error { routinePool <- struct{}{} wg.Add(1) go func() { - puller.PullOne(feed.ID) + // NOTE: do not use the incoming ctx, as it will be Done() automatically + // by api timeout middleware + puller.PullOne(context.Background(), feed.ID) <-routinePool wg.Done() }() @@ -118,13 +119,10 @@ func (f Feed) Create(req *ReqFeedCreate) error { }() return nil } - return puller.PullOne(feeds[0].ID) + return puller.PullOne(ctx, feeds[0].ID) } -func (f Feed) CheckValidity(req *ReqFeedCheckValidity) (*RespFeedCheckValidity, error) { - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - defer cancel() - +func (f Feed) CheckValidity(ctx context.Context, req *ReqFeedCheckValidity) (*RespFeedCheckValidity, error) { validLinks := make([]ValidityItem, 0) parsed, err := pull.Fetch(ctx, req.Link) if err == nil && parsed != nil { @@ -153,7 +151,7 @@ func (f Feed) CheckValidity(req *ReqFeedCheckValidity) (*RespFeedCheckValidity, }, nil } -func (f Feed) Update(req *ReqFeedUpdate) error { +func (f Feed) Update(ctx context.Context, req *ReqFeedUpdate) error { data := &model.Feed{ Name: req.Name, Link: req.Link, @@ -169,7 +167,7 @@ func (f Feed) Update(req *ReqFeedUpdate) error { return err } -func (f Feed) Delete(req *ReqFeedDelete) error { +func (f Feed) Delete(ctx context.Context, req *ReqFeedDelete) error { // FIX: transaction if err := f.itemRepo.DeleteByFeed(req.ID); err != nil { return err @@ -177,12 +175,14 @@ func (f Feed) Delete(req *ReqFeedDelete) error { return f.feedRepo.Delete(req.ID) } -func (f Feed) Refresh(req *ReqFeedRefresh) error { +func (f Feed) Refresh(ctx context.Context, req *ReqFeedRefresh) error { pull := pull.NewPuller(repo.NewFeed(repo.DB), repo.NewItem(repo.DB)) if req.ID != nil { - return pull.PullOne(*req.ID) + return pull.PullOne(ctx, *req.ID) } if req.All != nil && *req.All { + // NOTE: do not use the incoming ctx, as it will be Done() automatically + // by api timeout middleware go pull.PullAll(context.Background(), true) } return nil diff --git a/server/group.go b/server/group.go index c5e698b..a38fb74 100644 --- a/server/group.go +++ b/server/group.go @@ -1,6 +1,7 @@ package server import ( + "context" "errors" "net/http" @@ -32,7 +33,7 @@ func NewGroup(groupRepo GroupRepo, feedRepo FeedinGroupRepo) *Group { } } -func (g Group) All() (*RespGroupAll, error) { +func (g Group) All(ctx context.Context) (*RespGroupAll, error) { data, err := g.groupRepo.All() if err != nil { return nil, err @@ -50,7 +51,7 @@ func (g Group) All() (*RespGroupAll, error) { }, nil } -func (g Group) Create(req *ReqGroupCreate) error { +func (g Group) Create(ctx context.Context, req *ReqGroupCreate) error { newGroup := &model.Group{ Name: req.Name, } @@ -61,7 +62,7 @@ func (g Group) Create(req *ReqGroupCreate) error { return err } -func (g Group) Update(req *ReqGroupUpdate) error { +func (g Group) Update(ctx context.Context, req *ReqGroupUpdate) error { err := g.groupRepo.Update(req.ID, &model.Group{ Name: req.Name, }) @@ -71,7 +72,7 @@ func (g Group) Update(req *ReqGroupUpdate) error { return err } -func (g Group) Delete(req *ReqGroupDelete) error { +func (g Group) Delete(ctx context.Context, req *ReqGroupDelete) error { if req.ID == 1 { return errors.New("cannot delete the default group") } diff --git a/server/item.go b/server/item.go index cecc8a8..1e23ea2 100644 --- a/server/item.go +++ b/server/item.go @@ -1,6 +1,8 @@ package server import ( + "context" + "github.com/0x2e/fusion/model" "github.com/0x2e/fusion/repo" ) @@ -25,7 +27,7 @@ func NewItem(repo ItemRepo) *Item { } } -func (i Item) List(req *ReqItemList) (*RespItemList, error) { +func (i Item) List(ctx context.Context, req *ReqItemList) (*RespItemList, error) { filter := repo.ItemFilter{ Keyword: req.Keyword, FeedID: req.FeedID, @@ -66,7 +68,7 @@ func (i Item) List(req *ReqItemList) (*RespItemList, error) { }, nil } -func (i Item) Get(req *ReqItemGet) (*RespItemGet, error) { +func (i Item) Get(ctx context.Context, req *ReqItemGet) (*RespItemGet, error) { data, err := i.repo.Get(req.ID) if err != nil { return nil, err @@ -89,14 +91,14 @@ func (i Item) Get(req *ReqItemGet) (*RespItemGet, error) { }, nil } -func (i Item) Delete(req *ReqItemDelete) error { +func (i Item) Delete(ctx context.Context, req *ReqItemDelete) error { return i.repo.Delete(req.ID) } -func (i Item) UpdateUnread(req *ReqItemUpdateUnread) error { +func (i Item) UpdateUnread(ctx context.Context, req *ReqItemUpdateUnread) error { return i.repo.UpdateUnread(req.IDs, req.Unread) } -func (i Item) UpdateBookmark(req *ReqItemUpdateBookmark) error { +func (i Item) UpdateBookmark(ctx context.Context, req *ReqItemUpdateBookmark) error { return i.repo.UpdateBookmark(req.ID, req.Bookmark) } diff --git a/service/pull/handle.go b/service/pull/handle.go index fafe3c7..d72cdee 100644 --- a/service/pull/handle.go +++ b/service/pull/handle.go @@ -15,6 +15,8 @@ import ( ) func (p *Puller) do(ctx context.Context, f *model.Feed, force bool) error { + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() if f.IsSuspended() { log.Printf("skip feed %d: suspended\n", f.ID) return nil diff --git a/service/pull/pull.go b/service/pull/pull.go index 98f449d..59f31f4 100644 --- a/service/pull/pull.go +++ b/service/pull/pull.go @@ -38,19 +38,13 @@ func NewPuller(feedRepo FeedRepo, itemRepo ItemRepo) *Puller { var interval = 30 * time.Minute func (p *Puller) Run() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() ticker := time.NewTicker(interval) defer ticker.Stop() for { - p.PullAll(ctx, false) + p.PullAll(context.Background(), false) - select { - case <-ctx.Done(): - return - case <-ticker.C: - } + <-ticker.C } } @@ -90,14 +84,12 @@ func (p *Puller) PullAll(ctx context.Context, force bool) error { return nil } -func (p *Puller) PullOne(id uint) error { +func (p *Puller) PullOne(ctx context.Context, id uint) error { f, err := p.feedRepo.Get(id) if err != nil { log.Println(err) return err } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() return p.do(ctx, f, true) }