Skip to content

Commit

Permalink
Merge pull request #1628 from jinlinGuan/issue-1599
Browse files Browse the repository at this point in the history
fix: Remove device profile from the cache properly
  • Loading branch information
cloudxxx8 authored Oct 1, 2024
2 parents 224db1e + 7eb1c14 commit 0f2c62f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 17 deletions.
1 change: 1 addition & 0 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ The following steps show how to trigger profile scan on device-simple:
2. Trigger profile scan by sending POST request to DS endpoint: http://edgex-device-simple:59999/api/v3/profilescan with payload:
```json
{
"apiVersion": "v3",
"deviceName": "ProfileScan-Simple-Device",
"profileName": "ProfileScan-Test-Profile"
}
Expand Down
28 changes: 16 additions & 12 deletions internal/application/callback.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ func UpdateProfile(profileRequest requests.DeviceProfileRequest, dic *di.Contain
return nil
}

func DeleteProfile(profileName string, dic *di.Container) errors.EdgeX {
lc := bootstrapContainer.LoggingClientFrom(dic.Get)
if cache.CheckProfileNotUsed(profileName) {
err := cache.Profiles().RemoveByName(profileName)
if err != nil {
errMsg := fmt.Sprintf("failed to remove device profile %s", profileName)
return errors.NewCommonEdgeX(errors.KindServerError, errMsg, err)
}
lc.Debugf("profile %s is removed from cache", profileName)
} else {
lc.Warnf("received Profile Deletion System Event for %s, but the profile is still used by some devices", profileName)
}

return nil
}

func AddDevice(addDeviceRequest requests.AddDeviceRequest, dic *di.Container) errors.EdgeX {
device := dtos.ToDeviceModel(addDeviceRequest.Device)
lc := bootstrapContainer.LoggingClientFrom(dic.Get)
Expand Down Expand Up @@ -174,18 +190,6 @@ func DeleteDevice(name string, dic *di.Container) errors.EdgeX {
return errors.NewCommonEdgeX(errors.KindServerError, errMsg, err)
}

// a special case in which user updates the device profile after deleting all
// devices in metadata, the profile won't be correctly updated because metadata
// does not know which device service callback it needs to call. Remove the unused
// device profile in cache so that if it is updated in metadata, next time the
// device using it is added/updated, the cache can receive the updated one as well.
if device.ProfileName != "" && cache.CheckProfileNotUsed(device.ProfileName) {
edgexErr = cache.Profiles().RemoveByName(device.ProfileName)
if edgexErr != nil {
lc.Warn("failed to remove unused profile", edgexErr.DebugMessages())
}
}

return nil
}

Expand Down
23 changes: 18 additions & 5 deletions internal/controller/messaging/callback.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ func MetadataSystemEventsCallback(ctx context.Context, serviceBaseName string, d
deviceService := container.DeviceServiceFrom(dic.Get)
metadataSystemEventTopic := common.NewPathBuilder().EnableNameFieldEscape(configuration.Service.EnableNameFieldEscape).
SetPath(messageBusInfo.GetBaseTopicPrefix()).SetPath(common.MetadataSystemEventSubscribeTopic).SetNameFieldPath(deviceService.Name).SetPath("#").BuildPath()

lc.Infof("Subscribing to System Events on topic: %s", metadataSystemEventTopic)
profileDeleteSystemEventTopic := common.NewPathBuilder().EnableNameFieldEscape(configuration.Service.EnableNameFieldEscape).
SetPath(messageBusInfo.GetBaseTopicPrefix()).
SetPath(strings.Replace(common.MetadataSystemEventSubscribeTopic, "+/+", common.DeviceProfileSystemEventType+"/"+common.SystemEventActionDelete, 1)).
SetPath("#").BuildPath()
lc.Infof("Subscribing to System Events on topics: %s and %s", metadataSystemEventTopic, profileDeleteSystemEventTopic)

messages := make(chan types.MessageEnvelope, 1)
messageErrors := make(chan error, 1)
Expand All @@ -40,6 +43,10 @@ func MetadataSystemEventsCallback(ctx context.Context, serviceBaseName string, d
Topic: metadataSystemEventTopic,
Messages: messages,
},
{
Topic: profileDeleteSystemEventTopic,
Messages: messages,
},
}

// Must subscribe to provision watcher System Events separately when the service has an instance name. i.e. -i flag was used.
Expand Down Expand Up @@ -85,7 +92,11 @@ func MetadataSystemEventsCallback(ctx context.Context, serviceBaseName string, d
}

serviceName := container.DeviceServiceFrom(dic.Get).Name
if systemEvent.Owner != serviceName && systemEvent.Owner != serviceBaseName {
if systemEvent.Owner == common.CoreMetaDataServiceKey {
if systemEvent.Type != common.DeviceProfileSystemEventType && systemEvent.Action != common.SystemEventActionDelete {
lc.Errorf("only support device profile delete system events from owner %s", systemEvent.Owner)
}
} else if systemEvent.Owner != serviceName && systemEvent.Owner != serviceBaseName {
lc.Errorf("unmatched system event owner %s with service name %s", systemEvent.Owner, serviceName)
continue
}
Expand Down Expand Up @@ -155,8 +166,10 @@ func deviceProfileSystemEventAction(systemEvent dtos.SystemEvent, dic *di.Contai
switch systemEvent.Action {
case common.SystemEventActionUpdate:
err = application.UpdateProfile(requests.NewDeviceProfileRequest(deviceProfile), dic)
// there is no action needed for Device Profile Add and Delete in Device Service
case common.SystemEventActionAdd, common.SystemEventActionDelete:
case common.SystemEventActionDelete:
err = application.DeleteProfile(deviceProfile.Name, dic)
// there is no action needed for Device Profile Add in Device Service
case common.SystemEventActionAdd:
break
default:
return fmt.Errorf("unknown %s system event action %s", systemEvent.Type, systemEvent.Action)
Expand Down

0 comments on commit 0f2c62f

Please sign in to comment.