-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: FelixTing <felix@iotechsys.com>
- Loading branch information
Showing
11 changed files
with
275 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
// | ||
// Copyright (C) 2025 IOTech Ltd | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package application | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v4/bootstrap/container" | ||
"github.com/edgexfoundry/go-mod-bootstrap/v4/di" | ||
|
||
"github.com/edgexfoundry/go-mod-core-contracts/v4/common" | ||
"github.com/edgexfoundry/go-mod-core-contracts/v4/models" | ||
|
||
"github.com/edgexfoundry/device-sdk-go/v4/internal/cache" | ||
sdkCommon "github.com/edgexfoundry/device-sdk-go/v4/internal/common" | ||
"github.com/edgexfoundry/device-sdk-go/v4/internal/container" | ||
) | ||
|
||
func deviceReturn(deviceName string, dic *di.Container) { | ||
lc := bootstrapContainer.LoggingClientFrom(dic.Get) | ||
dc := bootstrapContainer.DeviceClientFrom(dic.Get) | ||
config := container.ConfigurationFrom(dic.Get) | ||
|
||
for { | ||
LOOP: | ||
time.Sleep(time.Duration(config.Device.DeviceDownTimeout) * time.Second) | ||
lc.Infof("Checking operational state for device: %s", deviceName) | ||
|
||
d, found := cache.Devices().ForName(deviceName) | ||
if !found { | ||
lc.Warnf("Device %s not found. Exiting retry loop.", deviceName) | ||
return | ||
} | ||
|
||
if d.OperatingState == models.Up { | ||
lc.Infof("Device %s is already operational. Exiting retry loop.", deviceName) | ||
return | ||
} | ||
|
||
p, found := cache.Profiles().ForName(d.ProfileName) | ||
if !found { | ||
lc.Warnf("Device %s has no profile. Cannot set operational state automatically.", deviceName) | ||
return | ||
} | ||
|
||
for _, dr := range p.DeviceResources { | ||
if dr.Properties.ReadWrite == common.ReadWrite_R || | ||
dr.Properties.ReadWrite == common.ReadWrite_RW || | ||
dr.Properties.ReadWrite == common.ReadWrite_WR { | ||
_, err := GetCommand(context.Background(), deviceName, dr.Name, "", true, dic) | ||
if err == nil { | ||
lc.Infof("Device %s responsive: setting operational state to up.", deviceName) | ||
sdkCommon.UpdateOperatingState(deviceName, models.Up, lc, dc) | ||
return | ||
} else { | ||
lc.Errorf("Device %s unresponsive: retrying in %v seconds.", deviceName, config.Device.DeviceDownTimeout) | ||
goto LOOP | ||
} | ||
} | ||
} | ||
lc.Infof("Device %s has no readable resources. Setting operational state to up without checking.", deviceName) | ||
sdkCommon.UpdateOperatingState(deviceName, models.Up, lc, dc) | ||
return | ||
} | ||
} | ||
|
||
func DeviceRequestFailed(deviceName string, dic *di.Container) { | ||
config := container.ConfigurationFrom(dic.Get) | ||
if config.Device.AllowedFails > 0 { | ||
lc := bootstrapContainer.LoggingClientFrom(dic.Get) | ||
dc := bootstrapContainer.DeviceClientFrom(dic.Get) | ||
reqFailsTracker := container.AllowedRequestFailuresTrackerFrom(dic.Get) | ||
|
||
if reqFailsTracker.Decrease(deviceName) == 0 { | ||
d, ok := cache.Devices().ForName(deviceName) | ||
if !ok { | ||
return | ||
} | ||
if d.OperatingState != models.Down { | ||
lc.Infof("Marking device %s non-operational", deviceName) | ||
sdkCommon.UpdateOperatingState(deviceName, models.Down, lc, dc) | ||
} | ||
if config.Device.DeviceDownTimeout > 0 { | ||
lc.Warnf("Will retry device %s in %v seconds", deviceName, config.Device.DeviceDownTimeout) | ||
go deviceReturn(deviceName, dic) | ||
} | ||
return | ||
} | ||
} | ||
} | ||
|
||
func DeviceRequestSucceeded(d models.Device, dic *di.Container) { | ||
config := container.ConfigurationFrom(dic.Get) | ||
reqFailsTracker := container.AllowedRequestFailuresTrackerFrom(dic.Get) | ||
if config.Device.AllowedFails > 0 && reqFailsTracker.Value(d.Name) < int(config.Device.AllowedFails) { | ||
reqFailsTracker.Set(d.Name, int(config.Device.AllowedFails)) | ||
if d.OperatingState == models.Down { | ||
lc := bootstrapContainer.LoggingClientFrom(dic.Get) | ||
dc := bootstrapContainer.DeviceClientFrom(dic.Get) | ||
sdkCommon.UpdateOperatingState(d.Name, models.Up, lc, dc) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
// | ||
// Copyright (C) 2025 IOTech Ltd | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package container | ||
|
||
import "github.com/edgexfoundry/device-sdk-go/v4/internal/syncutils" | ||
|
||
// AllowedFailuresTracker wraps a map of device names to atomic integers that track the number of allowed request | ||
// failures for each device. | ||
type AllowedFailuresTracker struct { | ||
data map[string]*syncutils.AtomicInt | ||
} | ||
|
||
// NewAllowedFailuresTracker creates and initializes a new tracker. | ||
func NewAllowedFailuresTracker() AllowedFailuresTracker { | ||
return AllowedFailuresTracker{ | ||
data: make(map[string]*syncutils.AtomicInt), | ||
} | ||
} | ||
|
||
// Get retrieves the AtomicInt for a given device name. | ||
// Returns nil if the device does not exist. | ||
func (aft *AllowedFailuresTracker) Get(deviceName string) *syncutils.AtomicInt { | ||
return aft.data[deviceName] | ||
} | ||
|
||
// Set initializes or updates the AtomicInt for a given device. | ||
func (aft *AllowedFailuresTracker) Set(deviceName string, value int) { | ||
if _, exists := aft.data[deviceName]; !exists { | ||
aft.data[deviceName] = &syncutils.AtomicInt{} | ||
} | ||
aft.data[deviceName].Set(value) | ||
} | ||
|
||
// Decrease decreases the AtomicInt value for a given device by 1. | ||
// Returns the updated value or -1 if the device does not exist. | ||
func (aft *AllowedFailuresTracker) Decrease(deviceName string) int { | ||
if atomicInt, exists := aft.data[deviceName]; exists { | ||
if atomicInt.Value() >= 0 { | ||
return atomicInt.Decrease() | ||
} | ||
} | ||
return -1 | ||
} | ||
|
||
// Value retrieves the current value of the AtomicInt for a device. | ||
// Returns -1 if the device does not exist. | ||
func (aft *AllowedFailuresTracker) Value(deviceName string) int { | ||
if atomicInt, exists := aft.data[deviceName]; exists { | ||
return atomicInt.Value() | ||
} | ||
return -1 | ||
} | ||
|
||
// Remove deletes the entry for a given device name from the tracker. | ||
func (aft *AllowedFailuresTracker) Remove(deviceName string) { | ||
delete(aft.data, deviceName) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.