From b8f1930dc664b1a8a7b86dc51264f2166c39c7ee Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Mon, 27 Apr 2026 08:15:11 -0700 Subject: [PATCH] chore(daemon): named timeout constants (#1027) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What? Replaces ad-hoc `60*time.Second` and `30*time.Second` literals in `daemon/handler.go` with two named constants and a brief comment documenting the split, exactly as suggested in the issue body. ```go const ( fetchTimeout = 60 * time.Second mutateTimeout = 30 * time.Second ) ``` `fetchTimeout` (was `60*time.Second`): - `handleFetchEmails` (line 129) - `handleFetchEmailBody` (line 154) - async fetch inside `handleMarkRead` (line 318) `mutateTimeout` (was `30*time.Second`): - `handleDeleteEmails` (line 193) - `handleArchiveEmails` (line 216) - `handleMoveEmails` (line 239) - `handleMarkRead` (line 262) - `handleFetchFolders` (line 287) ## Why? > `fetchTimeout` covers reads against the upstream IMAP provider, which can return large bodies and so are given more headroom. `mutateTimeout` covers state-changing operations and folder listings, which are bounded by IMAP command latency rather than payload size. If the maintainer wants `handleFetchFolders` reclassified to `fetchTimeout` (which would be a behavior change from 30s to 60s), happy to do that as a follow-up — kept it at the existing value here to keep this purely a refactor. Closes #985. Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> --- daemon/handler.go | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/daemon/handler.go b/daemon/handler.go index de2e73c73016132354fb23bd734aa55b6fef23da..2c59fb518b81da4fc5de39b4b64e39eaeb70f2c8 100644 --- a/daemon/handler.go +++ b/daemon/handler.go @@ -11,6 +11,15 @@ import ( "github.com/floatpane/matcha/daemonrpc" ) +// Per-handler timeouts. fetchTimeout covers reads against the upstream IMAP +// provider, which can return large bodies and so are given more headroom. +// mutateTimeout covers state-changing operations and folder listings, which +// are bounded by IMAP command latency rather than payload size. +const ( + fetchTimeout = 60 * time.Second + mutateTimeout = 30 * time.Second +) + func (d *Daemon) handleRequest(conn *daemonrpc.Conn, req *daemonrpc.Request) { switch req.Method { case daemonrpc.MethodPing: @@ -117,7 +126,7 @@ func (d *Daemon) handleFetchEmails(conn *daemonrpc.Conn, req *daemonrpc.Request) return } - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), fetchTimeout) defer cancel() emails, err := p.FetchEmails(ctx, params.Folder, params.Limit, params.Offset) @@ -142,7 +151,7 @@ func (d *Daemon) handleFetchEmailBody(conn *daemonrpc.Conn, req *daemonrpc.Reque return } - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), fetchTimeout) defer cancel() body, attachments, err := p.FetchEmailBody(ctx, params.Folder, params.UID) @@ -181,7 +190,7 @@ func (d *Daemon) handleDeleteEmails(conn *daemonrpc.Conn, req *daemonrpc.Request return } - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), mutateTimeout) defer cancel() if err := p.DeleteEmails(ctx, params.Folder, params.UIDs); err != nil { @@ -204,7 +213,7 @@ func (d *Daemon) handleArchiveEmails(conn *daemonrpc.Conn, req *daemonrpc.Reques return } - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), mutateTimeout) defer cancel() if err := p.ArchiveEmails(ctx, params.Folder, params.UIDs); err != nil { @@ -227,7 +236,7 @@ func (d *Daemon) handleMoveEmails(conn *daemonrpc.Conn, req *daemonrpc.Request) return } - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), mutateTimeout) defer cancel() if err := p.MoveEmails(ctx, params.UIDs, params.SourceFolder, params.DestFolder); err != nil { @@ -250,7 +259,7 @@ func (d *Daemon) handleMarkRead(conn *daemonrpc.Conn, req *daemonrpc.Request) { return } - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), mutateTimeout) defer cancel() // MarkAsRead only supports one UID at a time in the Provider interface. @@ -275,7 +284,7 @@ func (d *Daemon) handleFetchFolders(conn *daemonrpc.Conn, req *daemonrpc.Request return } - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), mutateTimeout) defer cancel() folders, err := p.FetchFolders(ctx) @@ -306,7 +315,7 @@ func (d *Daemon) handleRefreshFolder(conn *daemonrpc.Conn, req *daemonrpc.Reques Folder: params.Folder, }) - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), fetchTimeout) defer cancel() emails, err := p.FetchEmails(ctx, params.Folder, 50, 0)