From 46a18a9b1ca7e30e2e011ee6f54f1d62b98114eb Mon Sep 17 00:00:00 2001 From: Dennis Ahaus Date: Mon, 24 Nov 2025 10:13:42 +0100 Subject: [PATCH 1/8] Add ProcessLength to heartbeat event This change extends the heartbeat event payload to include ProcessLength, which represents the current number of running processes on the VM. By including process count in heartbeats, the bosh-monitor can now align its behavior with the bosh-cli 'vms' command output. This allows the monitor to react to process state changes in real-time without requiring separate get_state RPC calls --- agent/agent.go | 18 ++++++++++++------ agent/agent_test.go | 32 ++++++++++++++++++++++++++------ agent/heartbeat.go | 13 +++++++------ agent/heartbeat_test.go | 10 ++++++---- 4 files changed, 51 insertions(+), 22 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 93fea3659..9ae8ae5b1 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -183,13 +183,19 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { return Heartbeat{}, bosherr.WrapError(err, "Getting job spec") } + processes, err := a.jobSupervisor.Processes() + if err != nil { + return Heartbeat{}, bosherr.WrapError(err, "Getting processes") + } + hb := Heartbeat{ - Deployment: spec.Deployment, - Job: spec.JobSpec.Name, - Index: spec.Index, - JobState: status, - Vitals: vitals, - NodeID: spec.NodeID, + Deployment: spec.Deployment, + Job: spec.JobSpec.Name, + Index: spec.Index, + JobState: status, + Vitals: vitals, + NodeID: spec.NodeID, + ProcessLength: len(processes), } return hb, nil diff --git a/agent/agent_test.go b/agent/agent_test.go index 7983ad901..78d35a570 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -18,6 +18,7 @@ import ( fakeas "github.com/cloudfoundry/bosh-agent/v2/agent/applier/applyspec/fakes" fakeagent "github.com/cloudfoundry/bosh-agent/v2/agent/fakes" boshhandler "github.com/cloudfoundry/bosh-agent/v2/handler" + boshjobsuper "github.com/cloudfoundry/bosh-agent/v2/jobsupervisor" fakejobsuper "github.com/cloudfoundry/bosh-agent/v2/jobsupervisor/fakes" fakembus "github.com/cloudfoundry/bosh-agent/v2/mbus/fakes" "github.com/cloudfoundry/bosh-agent/v2/platform/platformfakes" @@ -125,6 +126,11 @@ func init() { //nolint:funlen,gochecknoinits } jobSupervisor.StatusStatus = "fake-state" + jobSupervisor.ProcessesStatus = []boshjobsuper.Process{ + {Name: "process1", State: "running"}, + {Name: "process2", State: "running"}, + {Name: "process3", State: "stopped"}, + } vitalService.GetReturns(boshvitals.Vitals{ Load: []string{"a", "b", "c"}, @@ -135,12 +141,13 @@ func init() { //nolint:funlen,gochecknoinits expectedJobIndex := 1 expectedNodeID := "node-id" expectedHb := agent.Heartbeat{ - Deployment: "FakeDeployment", - Job: &expectedJobName, - Index: &expectedJobIndex, - JobState: "fake-state", - NodeID: expectedNodeID, - Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, + Deployment: "FakeDeployment", + Job: &expectedJobName, + Index: &expectedJobIndex, + JobState: "fake-state", + NodeID: expectedNodeID, + Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, + ProcessLength: 3, } It("sends initial heartbeat", func() { @@ -247,6 +254,19 @@ func init() { //nolint:funlen,gochecknoinits }) }) + Context("when the boshAgent fails to get processes for a heartbeat", func() { + BeforeEach(func() { + jobSupervisor.ProcessesError = errors.New("fake-processes-error") + handler.KeepOnRunning() + }) + + It("returns the error", func() { + err := boshAgent.Run() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("fake-processes-error")) + }) + }) + It("sends job monitoring alerts to health manager", func() { handler.KeepOnRunning() diff --git a/agent/heartbeat.go b/agent/heartbeat.go index b3f8e58e1..413b1ee50 100644 --- a/agent/heartbeat.go +++ b/agent/heartbeat.go @@ -8,12 +8,13 @@ import ( // https://www.pivotaltracker.com/story/show/132265151 type Heartbeat struct { - Deployment string `json:"deployment"` - Job *string `json:"job"` - Index *int `json:"index"` - JobState string `json:"job_state"` - Vitals boshvitals.Vitals `json:"vitals"` - NodeID string `json:"node_id"` + Deployment string `json:"deployment"` + Job *string `json:"job"` + Index *int `json:"index"` + JobState string `json:"job_state"` + Vitals boshvitals.Vitals `json:"vitals"` + NodeID string `json:"node_id"` + ProcessLength int `json:"process_length"` } // Heartbeat payload example: diff --git a/agent/heartbeat_test.go b/agent/heartbeat_test.go index 8a5c5d756..b59d91cfd 100644 --- a/agent/heartbeat_test.go +++ b/agent/heartbeat_test.go @@ -29,10 +29,11 @@ func init() { //nolint:gochecknoinits "persistent": boshvitals.SpecificDiskVitals{}, }, }, - NodeID: "node-id", + NodeID: "node-id", + ProcessLength: 3, } - expectedJSON := `{"deployment":"FakeDeployment","job":"foo","index":0,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id"}` + expectedJSON := `{"deployment":"FakeDeployment","job":"foo","index":0,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","process_length":3}` hbBytes, err := json.Marshal(hb) Expect(err).ToNot(HaveOccurred()) @@ -52,10 +53,11 @@ func init() { //nolint:gochecknoinits "persistent": boshvitals.SpecificDiskVitals{}, }, }, - NodeID: "node-id", + NodeID: "node-id", + ProcessLength: 0, } - expectedJSON := `{"deployment":"FakeDeployment","job":null,"index":null,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id"}` + expectedJSON := `{"deployment":"FakeDeployment","job":null,"index":null,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","process_length":0}` hbBytes, err := json.Marshal(hb) Expect(err).ToNot(HaveOccurred()) From 0e3272deaeff5a394341b525435e2f53b7ee5f80 Mon Sep 17 00:00:00 2001 From: I766702 Date: Tue, 9 Dec 2025 15:22:17 +0100 Subject: [PATCH 2/8] changed ProcessLength to NumberOfProcesses --- agent/agent.go | 14 +++++++------- agent/agent_test.go | 14 +++++++------- agent/heartbeat.go | 14 +++++++------- agent/heartbeat_test.go | 12 ++++++------ 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 9ae8ae5b1..7795c3985 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -189,13 +189,13 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { } hb := Heartbeat{ - Deployment: spec.Deployment, - Job: spec.JobSpec.Name, - Index: spec.Index, - JobState: status, - Vitals: vitals, - NodeID: spec.NodeID, - ProcessLength: len(processes), + Deployment: spec.Deployment, + Job: spec.JobSpec.Name, + Index: spec.Index, + JobState: status, + Vitals: vitals, + NodeID: spec.NodeID, + NumberOfProcesses: len(processes), } return hb, nil diff --git a/agent/agent_test.go b/agent/agent_test.go index 78d35a570..e7cd186a6 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -141,13 +141,13 @@ func init() { //nolint:funlen,gochecknoinits expectedJobIndex := 1 expectedNodeID := "node-id" expectedHb := agent.Heartbeat{ - Deployment: "FakeDeployment", - Job: &expectedJobName, - Index: &expectedJobIndex, - JobState: "fake-state", - NodeID: expectedNodeID, - Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, - ProcessLength: 3, + Deployment: "FakeDeployment", + Job: &expectedJobName, + Index: &expectedJobIndex, + JobState: "fake-state", + NodeID: expectedNodeID, + Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, + NumberOfProcesses: 3, } It("sends initial heartbeat", func() { diff --git a/agent/heartbeat.go b/agent/heartbeat.go index 413b1ee50..e10faff5a 100644 --- a/agent/heartbeat.go +++ b/agent/heartbeat.go @@ -8,13 +8,13 @@ import ( // https://www.pivotaltracker.com/story/show/132265151 type Heartbeat struct { - Deployment string `json:"deployment"` - Job *string `json:"job"` - Index *int `json:"index"` - JobState string `json:"job_state"` - Vitals boshvitals.Vitals `json:"vitals"` - NodeID string `json:"node_id"` - ProcessLength int `json:"process_length"` + Deployment string `json:"deployment"` + Job *string `json:"job"` + Index *int `json:"index"` + JobState string `json:"job_state"` + Vitals boshvitals.Vitals `json:"vitals"` + NodeID string `json:"node_id"` + NumberOfProcesses int `json:"number_of_processes"` } // Heartbeat payload example: diff --git a/agent/heartbeat_test.go b/agent/heartbeat_test.go index b59d91cfd..31b614a42 100644 --- a/agent/heartbeat_test.go +++ b/agent/heartbeat_test.go @@ -29,11 +29,11 @@ func init() { //nolint:gochecknoinits "persistent": boshvitals.SpecificDiskVitals{}, }, }, - NodeID: "node-id", - ProcessLength: 3, + NodeID: "node-id", + NumberOfProcesses: 3, } - expectedJSON := `{"deployment":"FakeDeployment","job":"foo","index":0,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","process_length":3}` + expectedJSON := `{"deployment":"FakeDeployment","job":"foo","index":0,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","number_of_processes":3}` hbBytes, err := json.Marshal(hb) Expect(err).ToNot(HaveOccurred()) @@ -53,11 +53,11 @@ func init() { //nolint:gochecknoinits "persistent": boshvitals.SpecificDiskVitals{}, }, }, - NodeID: "node-id", - ProcessLength: 0, + NodeID: "node-id", + NumberOfProcesses: 0, } - expectedJSON := `{"deployment":"FakeDeployment","job":null,"index":null,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","process_length":0}` + expectedJSON := `{"deployment":"FakeDeployment","job":null,"index":null,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","number_of_processes":0}` hbBytes, err := json.Marshal(hb) Expect(err).ToNot(HaveOccurred()) From a0681a9a7c284d38d2468f46bfc15ea8577167a6 Mon Sep 17 00:00:00 2001 From: I766702 Date: Wed, 17 Dec 2025 14:13:18 +0100 Subject: [PATCH 3/8] changed NumberOfProcesses to pointer --- agent/agent.go | 3 ++- agent/agent_test.go | 16 +++++++++------- agent/heartbeat.go | 2 +- agent/heartbeat_test.go | 12 ++++++++---- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 7795c3985..43ec97a54 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -188,6 +188,7 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { return Heartbeat{}, bosherr.WrapError(err, "Getting processes") } + num := len(processes) hb := Heartbeat{ Deployment: spec.Deployment, Job: spec.JobSpec.Name, @@ -195,7 +196,7 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { JobState: status, Vitals: vitals, NodeID: spec.NodeID, - NumberOfProcesses: len(processes), + NumberOfProcesses: &num, } return hb, nil diff --git a/agent/agent_test.go b/agent/agent_test.go index e7cd186a6..4fe9e3ed7 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -141,15 +141,17 @@ func init() { //nolint:funlen,gochecknoinits expectedJobIndex := 1 expectedNodeID := "node-id" expectedHb := agent.Heartbeat{ - Deployment: "FakeDeployment", - Job: &expectedJobName, - Index: &expectedJobIndex, - JobState: "fake-state", - NodeID: expectedNodeID, - Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, - NumberOfProcesses: 3, + Deployment: "FakeDeployment", + Job: &expectedJobName, + Index: &expectedJobIndex, + JobState: "fake-state", + NodeID: expectedNodeID, + Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, } + num := 3 + expectedHb.NumberOfProcesses = &num + It("sends initial heartbeat", func() { // Configure periodic heartbeat every 5 hours // so that we are sure that we will not receive it diff --git a/agent/heartbeat.go b/agent/heartbeat.go index e10faff5a..5b6b82256 100644 --- a/agent/heartbeat.go +++ b/agent/heartbeat.go @@ -14,7 +14,7 @@ type Heartbeat struct { JobState string `json:"job_state"` Vitals boshvitals.Vitals `json:"vitals"` NodeID string `json:"node_id"` - NumberOfProcesses int `json:"number_of_processes"` + NumberOfProcesses *int `json:"number_of_processes"` } // Heartbeat payload example: diff --git a/agent/heartbeat_test.go b/agent/heartbeat_test.go index 31b614a42..38a9ddf8a 100644 --- a/agent/heartbeat_test.go +++ b/agent/heartbeat_test.go @@ -29,10 +29,12 @@ func init() { //nolint:gochecknoinits "persistent": boshvitals.SpecificDiskVitals{}, }, }, - NodeID: "node-id", - NumberOfProcesses: 3, + NodeID: "node-id", } + num := 3 + hb.NumberOfProcesses = &num + expectedJSON := `{"deployment":"FakeDeployment","job":"foo","index":0,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","number_of_processes":3}` hbBytes, err := json.Marshal(hb) @@ -53,10 +55,12 @@ func init() { //nolint:gochecknoinits "persistent": boshvitals.SpecificDiskVitals{}, }, }, - NodeID: "node-id", - NumberOfProcesses: 0, + NodeID: "node-id", } + num := 0 + hb.NumberOfProcesses = &num + expectedJSON := `{"deployment":"FakeDeployment","job":null,"index":null,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","number_of_processes":0}` hbBytes, err := json.Marshal(hb) From 71e5925895dcb440f52192500c40feb834da5028 Mon Sep 17 00:00:00 2001 From: I766702 Date: Wed, 17 Dec 2025 15:53:30 +0100 Subject: [PATCH 4/8] changed some variable names --- agent/agent.go | 4 ++-- agent/agent_test.go | 17 ++++++++--------- agent/heartbeat_test.go | 15 +++++++-------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 43ec97a54..a06c34adb 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -188,7 +188,7 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { return Heartbeat{}, bosherr.WrapError(err, "Getting processes") } - num := len(processes) + numberOfProcesses := len(processes) hb := Heartbeat{ Deployment: spec.Deployment, Job: spec.JobSpec.Name, @@ -196,7 +196,7 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { JobState: status, Vitals: vitals, NodeID: spec.NodeID, - NumberOfProcesses: &num, + NumberOfProcesses: &numberOfProcesses, } return hb, nil diff --git a/agent/agent_test.go b/agent/agent_test.go index 4fe9e3ed7..fd8e6637c 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -140,18 +140,17 @@ func init() { //nolint:funlen,gochecknoinits expectedJobName := "fake-job" expectedJobIndex := 1 expectedNodeID := "node-id" + expectedNumberOfProcesses := 3 expectedHb := agent.Heartbeat{ - Deployment: "FakeDeployment", - Job: &expectedJobName, - Index: &expectedJobIndex, - JobState: "fake-state", - NodeID: expectedNodeID, - Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, + Deployment: "FakeDeployment", + Job: &expectedJobName, + Index: &expectedJobIndex, + JobState: "fake-state", + NodeID: expectedNodeID, + Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, + NumberOfProcesses: &expectedNumberOfProcesses, } - num := 3 - expectedHb.NumberOfProcesses = &num - It("sends initial heartbeat", func() { // Configure periodic heartbeat every 5 hours // so that we are sure that we will not receive it diff --git a/agent/heartbeat_test.go b/agent/heartbeat_test.go index 38a9ddf8a..017b612cc 100644 --- a/agent/heartbeat_test.go +++ b/agent/heartbeat_test.go @@ -16,6 +16,7 @@ func init() { //nolint:gochecknoinits It("serializes heartbeat with all fields", func() { name := "foo" index := 0 + numberOfProcesses := 3 hb := Heartbeat{ Deployment: "FakeDeployment", @@ -29,12 +30,10 @@ func init() { //nolint:gochecknoinits "persistent": boshvitals.SpecificDiskVitals{}, }, }, - NodeID: "node-id", + NodeID: "node-id", + NumberOfProcesses: &numberOfProcesses, } - num := 3 - hb.NumberOfProcesses = &num - expectedJSON := `{"deployment":"FakeDeployment","job":"foo","index":0,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","number_of_processes":3}` hbBytes, err := json.Marshal(hb) @@ -45,6 +44,8 @@ func init() { //nolint:gochecknoinits Context("when job name, index are not available", func() { It("serializes job name and index as nulls to indicate that there is no job assigned to this agent", func() { + numberOfProcesses := 0 + hb := Heartbeat{ Deployment: "FakeDeployment", JobState: "running", @@ -55,12 +56,10 @@ func init() { //nolint:gochecknoinits "persistent": boshvitals.SpecificDiskVitals{}, }, }, - NodeID: "node-id", + NodeID: "node-id", + NumberOfProcesses: &numberOfProcesses, } - num := 0 - hb.NumberOfProcesses = &num - expectedJSON := `{"deployment":"FakeDeployment","job":null,"index":null,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","number_of_processes":0}` hbBytes, err := json.Marshal(hb) From 3ebb37d2a1c5eba8e00cac46b53cecbc8b477c31 Mon Sep 17 00:00:00 2001 From: I766702 Date: Thu, 18 Dec 2025 22:00:53 +0100 Subject: [PATCH 5/8] changed error handling when fetching processes --- agent/agent.go | 11 +++++------ agent/heartbeat_test.go | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index a06c34adb..07731d9f2 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -183,12 +183,12 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { return Heartbeat{}, bosherr.WrapError(err, "Getting job spec") } + var numberOfProcesses *int processes, err := a.jobSupervisor.Processes() - if err != nil { - return Heartbeat{}, bosherr.WrapError(err, "Getting processes") + if err == nil { + n := len(processes) + numberOfProcesses = &n } - - numberOfProcesses := len(processes) hb := Heartbeat{ Deployment: spec.Deployment, Job: spec.JobSpec.Name, @@ -196,9 +196,8 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { JobState: status, Vitals: vitals, NodeID: spec.NodeID, - NumberOfProcesses: &numberOfProcesses, + NumberOfProcesses: numberOfProcesses, } - return hb, nil } diff --git a/agent/heartbeat_test.go b/agent/heartbeat_test.go index 017b612cc..75cd97892 100644 --- a/agent/heartbeat_test.go +++ b/agent/heartbeat_test.go @@ -66,6 +66,27 @@ func init() { //nolint:gochecknoinits Expect(err).ToNot(HaveOccurred()) Expect(string(hbBytes)).To(Equal(expectedJSON)) }) + + It("serializes NumberOfProcesses as null when not available", func() { + hb := Heartbeat{ + Deployment: "FakeDeployment", + JobState: "running", + Vitals: boshvitals.Vitals{ + Disk: boshvitals.DiskVitals{ + "system": boshvitals.SpecificDiskVitals{}, + "ephemeral": boshvitals.SpecificDiskVitals{}, + "persistent": boshvitals.SpecificDiskVitals{}, + }, + }, + NodeID: "node-id", + } + + expectedJSON := `{"deployment":"FakeDeployment","job":null,"index":null,"job_state":"running","vitals":{"cpu":{},"disk":{"ephemeral":{},"persistent":{},"system":{}},"mem":{},"swap":{},"uptime":{}},"node_id":"node-id","number_of_processes":null}` + + hbBytes, err := json.Marshal(hb) + Expect(err).ToNot(HaveOccurred()) + Expect(string(hbBytes)).To(Equal(expectedJSON)) + }) }) }) } From f1967f56d495ff64633c4fdc5d00c510f809e865 Mon Sep 17 00:00:00 2001 From: I766702 Date: Fri, 19 Dec 2025 11:53:43 +0100 Subject: [PATCH 6/8] adjusted agent test --- agent/agent_test.go | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/agent/agent_test.go b/agent/agent_test.go index fd8e6637c..5442c92ba 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -257,14 +257,50 @@ func init() { //nolint:funlen,gochecknoinits Context("when the boshAgent fails to get processes for a heartbeat", func() { BeforeEach(func() { + jobName := "fake-job" + nodeID := "node-id" + jobIndex := 1 + specService.Spec = boshas.V1ApplySpec{ + Deployment: "FakeDeployment", + JobSpec: boshas.JobSpec{Name: &jobName}, + Index: &jobIndex, + NodeID: nodeID, + } + + jobSupervisor.StatusStatus = "fake-state" jobSupervisor.ProcessesError = errors.New("fake-processes-error") + + vitalService.GetReturns(boshvitals.Vitals{ + Load: []string{"a", "b", "c"}, + }, nil) + handler.KeepOnRunning() + handler.SendErr = errors.New("stop") }) - It("returns the error", func() { + It("sends heartbeat with NumberOfProcesses as nil", func() { err := boshAgent.Run() Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("fake-processes-error")) + Expect(err.Error()).To(ContainSubstring("stop")) + Expect(err.Error()).ToNot(ContainSubstring("fake-processes-error")) + + expectedJobName := "fake-job" + expectedJobIndex := 1 + expectedHb := agent.Heartbeat{ + Deployment: "FakeDeployment", + Job: &expectedJobName, + Index: &expectedJobIndex, + JobState: "fake-state", + NodeID: "node-id", + Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, + NumberOfProcesses: nil, + } + + Expect(handler.SendInputs()).To(ContainElement(fakembus.SendInput{ + Target: boshhandler.HealthMonitor, + Topic: boshhandler.Heartbeat, + Message: expectedHb, + })) }) }) From 4a9aa49ea2fdd4a4a58dd26fdeac29e4aafc6c14 Mon Sep 17 00:00:00 2001 From: yuriadam-sap Date: Mon, 29 Dec 2025 14:28:51 +0100 Subject: [PATCH 7/8] Added the error log if fetching processes fails Co-authored-by: Ruben Koster --- agent/agent.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 07731d9f2..bb577a6e8 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -185,9 +185,11 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { var numberOfProcesses *int processes, err := a.jobSupervisor.Processes() - if err == nil { - n := len(processes) - numberOfProcesses = &n + if err != nil { + a.logger.Debug(agentLogTag, "Failed to get processes for heartbeat: %s", err.Error()) + } else { + n := len(processes) + numberOfProcesses = &n } hb := Heartbeat{ Deployment: spec.Deployment, From 1bf632fa1568f623605d4246b9b92cca8f510eaf Mon Sep 17 00:00:00 2001 From: I766702 Date: Wed, 7 Jan 2026 15:28:47 +0100 Subject: [PATCH 8/8] fixed lint test --- agent/agent.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index bb577a6e8..e4329cc9b 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -186,10 +186,10 @@ func (a Agent) getHeartbeat(status string) (Heartbeat, error) { var numberOfProcesses *int processes, err := a.jobSupervisor.Processes() if err != nil { - a.logger.Debug(agentLogTag, "Failed to get processes for heartbeat: %s", err.Error()) + a.logger.Debug(agentLogTag, "Failed to get processes for heartbeat: %s", err.Error()) } else { - n := len(processes) - numberOfProcesses = &n + n := len(processes) + numberOfProcesses = &n } hb := Heartbeat{ Deployment: spec.Deployment,