diff --git a/CHANGELOG.md b/CHANGELOG.md index 61ff51aca5a..c285d7c043e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ ## 🐛 Bug Fixes +- fix(api): check `/health/readyz` immediately on startup instead of waiting for the first one-minute polling interval. - fix(docker): update Debian from bullseye to trixie for `lotus-builder` and `lotus-base` stages; also fetch prebuilt filecoin-ffi libraries instead of compiling them. ([filecoin-project/lotus#13785](https://github.com/filecoin-project/lotus/pull/13785)) - fix(eth): prevent `eth_getLogs` from returning successful empty or partial results when historical event-index coverage is incomplete. Block-hash queries now require a completed block event index, and range queries verify every canonical non-null tipset before returning logs. ([filecoin-project/lotus#13749](https://github.com/filecoin-project/lotus/issues/13749)) - fix(eth): prevent `eth_getTransactionReceipt` from returning a successful receipt with an empty `logs` array while that transaction's events are still being indexed. The call now fails until event indexing is complete, while transactions that completed with no events still return an empty array. ([filecoin-project/lotus#13758](https://github.com/filecoin-project/lotus/issues/13758)) diff --git a/node/health.go b/node/health.go index 5e3a3d7e91b..39771f20b6e 100644 --- a/node/health.go +++ b/node/health.go @@ -98,18 +98,23 @@ func NewReadyHandler(api lapi.FullNode) *HealthHandler { h := HealthHandler{} go func() { const heightTolerance = uint64(5) - var nethealth, synchealth bool + check := func() { + netstat, err := api.NetAutoNatStatus(ctx) + nethealth := err == nil && netstat.Reachability != network.ReachabilityUnknown + + nodestat, err := api.NodeStatus(ctx, false) + synchealth := err == nil && nodestat.SyncStatus.Behind < heightTolerance + + h.SetHealthy(nethealth && synchealth) + } + + check() + minutely := time.NewTicker(time.Minute) for { select { case <-minutely.C: - netstat, err := api.NetAutoNatStatus(ctx) - nethealth = err == nil && netstat.Reachability != network.ReachabilityUnknown - - nodestat, err := api.NodeStatus(ctx, false) - synchealth = err == nil && nodestat.SyncStatus.Behind < heightTolerance - - h.SetHealthy(nethealth && synchealth) + check() } } }() diff --git a/node/health_test.go b/node/health_test.go new file mode 100644 index 00000000000..f44ebcf8a82 --- /dev/null +++ b/node/health_test.go @@ -0,0 +1,34 @@ +package node + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/libp2p/go-libp2p/core/network" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/mocks" +) + +func TestNewReadyHandlerChecksImmediately(t *testing.T) { + ctrl := gomock.NewController(t) + fullNode := mocks.NewMockFullNode(ctrl) + fullNode.EXPECT().NetAutoNatStatus(gomock.Any()).Return(api.NatInfo{ + Reachability: network.ReachabilityPublic, + }, nil).AnyTimes() + fullNode.EXPECT().NodeStatus(gomock.Any(), false).Return(api.NodeStatus{ + SyncStatus: api.NodeSyncStatus{Behind: 0}, + }, nil).AnyTimes() + + handler := NewReadyHandler(fullNode) + + require.Eventually(t, func() bool { + response := httptest.NewRecorder() + handler.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/health/readyz", nil)) + return response.Code == http.StatusOK + }, time.Second, 10*time.Millisecond) +}