Replace string-matched netlink timeout detection with net.Error #65
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
keyop-go/nfq_forwarder!65
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue16_error_handling"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #16 (https://gitlab.keyop.co.uk/keyop/go/nfq_forwarder/-/issues/16).
Background
nfErrorFunctionis registered asgo-nfqueue's error callback viaRegisterWithErrorFunc, againstinitNfqueue'snfqueue.Config{ReadTimeout: 10 * time.Millisecond, ...}. That read timeout is howgo-nfqueue's internal read loop periodically wakes up to check for context cancellation - sonfErrorFunctionis called roughly every 10ms whenever no packet is waiting on the queue, confirming the "we may get called a lot" comment already on the ticket. It needs to correctly and cheaply recognise "this is just the routine timeout wakeup" on every one of those calls.The existing implementation did that by comparing
err.Error()against two hardcoded strings ("netlink receive: i/o timeout"/"netlink receive: recvmsg: i/o timeout") - fragile, since that formatted text is an implementation detail ofmdlayher/netlink.OpError'sError()method, not a documented contract, and has already taken two different shapes depending on exactly how the underlying read failed.Fix
mdlayher/netlink.OpError(the actual concrete error typeConn.Receive()returns) already implements the standardnet.Errorinterface, including a correctTimeout() bool. Replaced the string comparison with:This is robust to message-text changes across dependency versions (checks behavior/type, not formatted text), and - unlike the string comparison - also correctly recognises a timeout even if some future code wraps the error further, since
errors.Aswalks the fullUnwrap()chain.No behavior change for real production traffic - this is purely a correctness/robustness fix for how "is this a benign read-timeout" is detected.
Testing
TestNfErrorFunctionnow constructs a real*netlink.OpErrorwrapping a real timeout-capable error (os.ErrDeadlineExceeded) instead of a plain string, plus that same error wrapped an extra level deeper viafmt.Errorf("...: %w", ...)- a genuine regression case the old implementation got wrong (the wrapped error's formatted text no longer matches either hardcoded string, so it would have been incorrectly logged as a real error every ~10ms). The plain non-timeout "still logs" case is unchanged.go build ./...,go vet ./...make lint(golangci-lint + yamllint) -go mod tidypromotedmdlayher/netlinkfrom an indirect to a direct dependency, since the test now imports it directlymake test(go test -race -cover ./...)Docs
Updated
CLAUDE.md's Design notes and Testing sections.changed the description
requested review from @danny
assigned to @danny
Built and tested Ok. This seems to resolve the issue.
approved this merge request
mentioned in commit
50948e433bmentioned in issue #16
mentioned in commit
deb90f12e0