Repository: edgexfoundry/device-sdk-go (go)

Issue:
Service Name in Provision Watcher prevents multiple instance of service using same Provision Watcher
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅

Hello there! 😄

To expedite issue processing please search open and closed issues before submitting a new one.
Existing issues often contain information about workarounds, resolution, or progress updates.

Please do not remove sections of this template when submitting your issue.  If the section is not relevant to your issue, leave the section but enter "n/a" for not applicable.

Note some sections are marked "REQUIRED" and must be provided.  Never mark required sections "n/a".

🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->


# 🐞 Bug Report

### Affected Services [**REQUIRED**]
<!-- Can you pin-point one or more EdgeX services (Data, Metadata, Command, etc...) as the source of the bug? -->
<!-- ✍️edit: --> The issue is located in **Auto Provisioning**


### Is this a regression? No


### Description and Minimal Reproduction [**REQUIRED**]
The SDK uses the service name from the Provision Watcher when added new device. This creates an issue when running second instance of a service since the service name in the Provision Watcher matches the original service name.

The SDK should instead use the current services name in the new device. This allows the static provision watch to be reused across multiple instances. 



## 🌍  Your Environment
**Deployment Environment:**

**EdgeX Version [**REQUIRED**]:**


**Anything else relevant?**



Pull request description:
feat: Enhance autodiscovery to better support  multiple instances of same device service

closes #1437

<!-- Expected Commit Message Description (imported automatically by GitHub) -->
<!-- Must conform to [conventional commits guidelines](https://github.com/edgexfoundry/device-sdk-go/blob/main/.github/Contributing.md) -->
<!-- Expected Commit message must contain Closes/Fixes #IssueNumber statement when there is a related issue -->

<!-- Add additional detailed description of need for change if no related issue -->

**If your build fails** due to your commit message not passing the build checks, please review the guidelines here: https://github.com/edgexfoundry/device-sdk-go/blob/main/.github/Contributing.md

## PR Checklist
Please check if your PR fulfills the following requirements:

- [x] I am not introducing a breaking change (if you are, flag in conventional commit message with `BREAKING CHANGE:` describing the break)
- [x] I am not introducing a new dependency (add notes below if you are)
- [x] I have added unit tests for the new feature or bug fix (if not, why?)
- [x] I have fully tested (add details below) this the new feature or bug fix (if not, why?)
- [ ] I have opened a PR for the related docs change (if not, why?)
  <link to docs PR>

## Testing Instructions
TBD

## New Dependency Instructions (If applicable)
<!-- Please follow [vetting instructions](https://wiki.edgexfoundry.org/display/FA/Vetting+Process+for+3rd+Party+Dependencies) and place results here -->

Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 0b31e0be..09d80b7f 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -5,3 +5,12 @@ updates:
     directory: "/"
     schedule:
       interval: "daily"
+    ignore:
+      - dependency-name: "github.com/edgexfoundry/go-mod-core-contracts/v3"
+        # Included when go-mod-bootstrap is updated
+      - dependency-name: "github.com/edgexfoundry/go-mod-messaging/v3"
+        # Included when go-mod-bootstrap is updated
+      - dependency-name: "github.com/edgexfoundry/go-mod-registry/v3"
+        # Included when go-mod-bootstrap is updated
+      - dependency-name: "github.com/edgexfoundry/go-mod-secrets/v3"
+        # Included when go-mod-bootstrap is updated
\ No newline at end of file
diff --git a/go.mod b/go.mod
index ba638293..657624ae 100644
--- a/go.mod
+++ b/go.mod
@@ -4,9 +4,9 @@ go 1.20
 
 require (
 	github.com/OneOfOne/xxhash v1.2.8
-	github.com/edgexfoundry/go-mod-bootstrap/v3 v3.0.0-dev.75
-	github.com/edgexfoundry/go-mod-core-contracts/v3 v3.0.0-dev.38
-	github.com/edgexfoundry/go-mod-messaging/v3 v3.0.0-dev.26
+	github.com/edgexfoundry/go-mod-bootstrap/v3 v3.0.0-dev.83
+	github.com/edgexfoundry/go-mod-core-contracts/v3 v3.0.0-dev.40
+	github.com/edgexfoundry/go-mod-messaging/v3 v3.0.0-dev.29
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/mux v1.8.0
 	github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
@@ -22,7 +22,7 @@ require (
 	github.com/eclipse/paho.mqtt.golang v1.4.2 // indirect
 	github.com/edgexfoundry/go-mod-configuration/v3 v3.0.0-dev.10 // indirect
 	github.com/edgexfoundry/go-mod-registry/v3 v3.0.0-dev.7 // indirect
-	github.com/edgexfoundry/go-mod-secrets/v3 v3.0.0-dev.14 // indirect
+	github.com/edgexfoundry/go-mod-secrets/v3 v3.0.0-dev.15 // indirect
 	github.com/fatih/color v1.9.0 // indirect
 	github.com/fxamacker/cbor/v2 v2.4.0 // indirect
 	github.com/go-jose/go-jose/v3 v3.0.0 // indirect
@@ -30,7 +30,7 @@ require (
 	github.com/go-logfmt/logfmt v0.5.1 // indirect
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
-	github.com/go-playground/validator/v10 v10.12.0 // indirect
+	github.com/go-playground/validator/v10 v10.13.0 // indirect
 	github.com/go-redis/redis/v7 v7.3.0 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
@@ -43,7 +43,7 @@ require (
 	github.com/hashicorp/go-rootcerts v1.0.2 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/hashicorp/serf v0.10.1 // indirect
-	github.com/leodido/go-urn v1.2.2 // indirect
+	github.com/leodido/go-urn v1.2.3 // indirect
 	github.com/mattn/go-colorable v0.1.12 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect
 	github.com/mitchellh/consulstructure v0.0.0-20190329231841-56fdc4d2da54 // indirect
@@ -51,7 +51,7 @@ require (
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/mitchellh/reflectwalk v1.0.2 // indirect
-	github.com/nats-io/nats.go v1.24.0 // indirect
+	github.com/nats-io/nats.go v1.25.0 // indirect
 	github.com/nats-io/nkeys v0.4.4 // indirect
 	github.com/nats-io/nuid v1.0.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index 88294fbb..585b63f5 100644
--- a/go.sum
+++ b/go.sum
@@ -27,18 +27,18 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/eclipse/paho.mqtt.golang v1.4.2 h1:66wOzfUHSSI1zamx7jR6yMEI5EuHnT1G6rNA5PM12m4=
 github.com/eclipse/paho.mqtt.golang v1.4.2/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
-github.com/edgexfoundry/go-mod-bootstrap/v3 v3.0.0-dev.75 h1:3lisltPpqrviTORVuk3vs3xkV3Qg+DjUKbtjaOKvntg=
-github.com/edgexfoundry/go-mod-bootstrap/v3 v3.0.0-dev.75/go.mod h1:FT9MJ/Zpcehi02K1f4NJzumLaTrJvONm7v8uByyRjpg=
+github.com/edgexfoundry/go-mod-bootstrap/v3 v3.0.0-dev.83 h1:uEp7slcjUzvuI8AXlWxRGHH/SCeyX91AbhreQIEwitw=
+github.com/edgexfoundry/go-mod-bootstrap/v3 v3.0.0-dev.83/go.mod h1:WLCIPOYFpHZfIHWoLKWqYjGve+CDV7wd0JHc+Le9KMY=
 github.com/edgexfoundry/go-mod-configuration/v3 v3.0.0-dev.10 h1:iDuAO3vpBQnlQuFhai/NATbJkiYXxo3bPCtSnFl07Yw=
 github.com/edgexfoundry/go-mod-configuration/v3 v3.0.0-dev.10/go.mod h1:8RlYm5CPzZgUsfXDWVP1TIeUMhsDNIdRdj1HXdomtOI=
-github.com/edgexfoundry/go-mod-core-contracts/v3 v3.0.0-dev.38 h1:FSu4b6DqviexPsS/ECBR9YgkVB76VSgyMCMDUvyGgNM=
-github.com/edgexfoundry/go-mod-core-contracts/v3 v3.0.0-dev.38/go.mod h1:1YS2J5NfPCd7TYBk0alu+RR5EBzBb+bnG0KF1qNRQYY=
-github.com/edgexfoundry/go-mod-messaging/v3 v3.0.0-dev.26 h1:PbWRMnOxZusSGj/ZFkrgbEwG+TgVNrQed36pr96ytxM=
-github.com/edgexfoundry/go-mod-messaging/v3 v3.0.0-dev.26/go.mod h1:04phI5qPCFC2bfG1xZ5h6aiGH8Zp8gKDEljHjo/B+Fs=
+github.com/edgexfoundry/go-mod-core-contracts/v3 v3.0.0-dev.40 h1:30hNBz5Hrhp4gRBs3oXJaOIAtklZ+yrD5EqVXjlwRgE=
+github.com/edgexfoundry/go-mod-core-contracts/v3 v3.0.0-dev.40/go.mod h1:zzzWGWij6wAqm1go9TLs++TFMIsBqBb1eRnIj4mRxGw=
+github.com/edgexfoundry/go-mod-messaging/v3 v3.0.0-dev.29 h1:Sp0qCNED+gVSwiF7jssq7Txi67fPqAE7+YIEGh4K7hI=
+github.com/edgexfoundry/go-mod-messaging/v3 v3.0.0-dev.29/go.mod h1:/hUUM2+h8ajcQlNuyxCM6PeDE1Tz1S/EfvR4TmJAja8=
 github.com/edgexfoundry/go-mod-registry/v3 v3.0.0-dev.7 h1:sje0agoLi8ayEFxGO3xtN7P/IXwjZUUxpC8G2fCTu44=
 github.com/edgexfoundry/go-mod-registry/v3 v3.0.0-dev.7/go.mod h1:SGyo4fAHzOhDAd2Usa9RaBT/sOzkbceIqLrDG0+iYy8=
-github.com/edgexfoundry/go-mod-secrets/v3 v3.0.0-dev.14 h1:2jG1CBKBXPQdkM8AN1PweaTIaCgudZ6tua/BBBHgq+A=
-github.com/edgexfoundry/go-mod-secrets/v3 v3.0.0-dev.14/go.mod h1:FRKg6x/tVpYHfy/aMy5flTxxw3+YeYaQds8csCUqNTE=
+github.com/edgexfoundry/go-mod-secrets/v3 v3.0.0-dev.15 h1:i58fwqZYksuC6IkdDENBluE7084tBn4O5uv4oV4I1mI=
+github.com/edgexfoundry/go-mod-secrets/v3 v3.0.0-dev.15/go.mod h1:+JOtlbiePy66w2zsUFdSWC9fWoL9xPceKdbE98IZFHc=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
@@ -60,8 +60,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
-github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
+github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ=
+github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4=
 github.com/go-redis/redis/v7 v7.3.0 h1:3oHqd0W7f/VLKBxeYTEpqdMUsmMectngjM9OtoRoIgg=
 github.com/go-redis/redis/v7 v7.3.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -137,8 +137,8 @@ github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
-github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
+github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA=
+github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -175,8 +175,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nats-io/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4=
 github.com/nats-io/nats-server/v2 v2.9.16 h1:SuNe6AyCcVy0g5326wtyU8TdqYmcPqzTjhkHojAjprc=
-github.com/nats-io/nats.go v1.24.0 h1:CRiD8L5GOQu/DcfkmgBcTTIQORMwizF+rPk6T0RaHVQ=
-github.com/nats-io/nats.go v1.24.0/go.mod h1:dVQF+BK3SzUZpwyzHedXsvH3EO38aVKuOPkkHlv5hXA=
+github.com/nats-io/nats.go v1.25.0 h1:t5/wCPGciR7X3Mu8QOi4jiJaXaWM8qtkLu4lzGZvYHE=
+github.com/nats-io/nats.go v1.25.0/go.mod h1:D2WALIhz7V8M0pH8Scx8JZXlg6Oqz5VG+nQkK8nJdvg=
 github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
 github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
 github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
@@ -209,7 +209,6 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
 github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
diff --git a/internal/cache/init.go b/internal/cache/init.go
index f463bd72..5227c6d5 100644
--- a/internal/cache/init.go
+++ b/internal/cache/init.go
@@ -18,13 +18,13 @@ import (
 )
 
 // InitCache Init basic state for cache
-func InitCache(name string, dic *di.Container) errors.EdgeX {
+func InitCache(instanceName string, baseName string, dic *di.Container) errors.EdgeX {
 	dc := bootstrapContainer.DeviceClientFrom(dic.Get)
 	dpc := bootstrapContainer.DeviceProfileClientFrom(dic.Get)
 	pwc := bootstrapContainer.ProvisionWatcherClientFrom(dic.Get)
 
 	// init device cache
-	deviceRes, err := dc.DevicesByServiceName(context.Background(), name, 0, -1)
+	deviceRes, err := dc.DevicesByServiceName(context.Background(), instanceName, 0, -1)
 	if err != nil {
 		return err
 	}
@@ -46,7 +46,7 @@ func InitCache(name string, dic *di.Container) errors.EdgeX {
 	newProfileCache(profiles)
 
 	// init provision watcher cache
-	pwRes, err := pwc.ProvisionWatchersByServiceName(context.Background(), name, 0, -1)
+	pwRes, err := pwc.ProvisionWatchersByServiceName(context.Background(), baseName, 0, -1)
 	if err != nil {
 		return err
 	}
diff --git a/internal/controller/messaging/callback.go b/internal/controller/messaging/callback.go
index 05e61ccd..7ad28de8 100644
--- a/internal/controller/messaging/callback.go
+++ b/internal/controller/messaging/callback.go
@@ -9,6 +9,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"strings"
 
 	bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container"
 	"github.com/edgexfoundry/go-mod-bootstrap/v3/di"
@@ -22,7 +23,7 @@ import (
 	"github.com/edgexfoundry/device-sdk-go/v3/internal/container"
 )
 
-func MetadataSystemEventsCallback(ctx context.Context, dic *di.Container) errors.EdgeX {
+func MetadataSystemEventsCallback(ctx context.Context, serviceBaseName string, dic *di.Container) errors.EdgeX {
 	lc := bootstrapContainer.LoggingClientFrom(dic.Get)
 	messageBusInfo := container.ConfigurationFrom(dic.Get).MessageBus
 	deviceService := container.DeviceServiceFrom(dic.Get)
@@ -40,6 +41,24 @@ func MetadataSystemEventsCallback(ctx context.Context, dic *di.Container) errors
 		},
 	}
 
+	// Must subscribe to provision watcher System Events separately when the service has an instance name. i.e. -i flag was used.
+	// This is because Provision Watchers apply to all instances of the device service, i.e. the service base name (without the instance portion).
+	// The above subscribe topic is for the specific instance name which is appropriate for Devices, Profiles and Devices service System Events
+	// and when the -i flag is not used.
+	if serviceBaseName != deviceService.Name {
+		// Must replace the first wildcard with the type for Provision Watchers
+		baseSubscribeTopic := strings.Replace(common.MetadataSystemEventSubscribeTopic, "+", common.ProvisionWatcherSystemEventType, 1)
+		provisionWatcherSystemEventSubscribeTopic := common.BuildTopic(messageBusInfo.GetBaseTopicPrefix(),
+			baseSubscribeTopic, serviceBaseName, "#")
+
+		topics = append(topics, types.TopicChannel{
+			Topic:    provisionWatcherSystemEventSubscribeTopic,
+			Messages: messages,
+		})
+
+		lc.Infof("Subscribing additionally to Provision Watcher System Events on topic: %s", provisionWatcherSystemEventSubscribeTopic)
+	}
+
 	messageBus := bootstrapContainer.MessagingClientFrom(dic.Get)
 	err := messageBus.Subscribe(topics, messageErrors)
 	if err != nil {
@@ -65,7 +84,7 @@ func MetadataSystemEventsCallback(ctx context.Context, dic *di.Container) errors
 				}
 
 				serviceName := container.DeviceServiceFrom(dic.Get).Name
-				if systemEvent.Owner != serviceName {
+				if systemEvent.Owner != serviceName && systemEvent.Owner != serviceBaseName {
 					lc.Errorf("unmatched system event owner %s with service name %s", systemEvent.Owner, serviceName)
 					continue
 				}
diff --git a/internal/provision/devices.go b/internal/provision/devices.go
index 1010f8eb..64bb3f33 100644
--- a/internal/provision/devices.go
+++ b/internal/provision/devices.go
@@ -10,6 +10,8 @@ package provision
 import (
 	"context"
 	"encoding/json"
+	"fmt"
+	"net/http"
 	"os"
 	"path/filepath"
 	"strings"
@@ -22,6 +24,7 @@ import (
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/errors"
 	"github.com/edgexfoundry/go-mod-core-contracts/v3/models"
 	"github.com/google/uuid"
+	"github.com/hashicorp/go-multierror"
 	"gopkg.in/yaml.v3"
 
 	"github.com/edgexfoundry/device-sdk-go/v3/internal/cache"
@@ -104,6 +107,26 @@ func LoadDevices(path string, dic *di.Container) errors.EdgeX {
 	}
 	dc := bootstrapContainer.DeviceClientFrom(dic.Get)
 	ctx := context.WithValue(context.Background(), common.CorrelationHeader, uuid.NewString()) //nolint: staticcheck
-	_, edgexErr := dc.Add(ctx, addDevicesReq)
-	return edgexErr
+	responses, edgexErr := dc.Add(ctx, addDevicesReq)
+	if edgexErr != nil {
+		return edgexErr
+	}
+
+	err = nil
+	for _, response := range responses {
+		if response.StatusCode != http.StatusCreated {
+			if response.StatusCode == http.StatusConflict {
+				lc.Warnf("%s. Device may be owned by other device service instance.", response.Message)
+				continue
+			}
+
+			err = multierror.Append(err, fmt.Errorf("add device failed: %s", response.Message))
+		}
+	}
+
+	if err != nil {
+		return errors.NewCommonEdgeXWrapper(err)
+	}
+
+	return nil
 }
diff --git a/pkg/service/async.go b/pkg/service/async.go
index 7eb60bd3..e3a103f3 100644
--- a/pkg/service/async.go
+++ b/pkg/service/async.go
@@ -106,7 +106,7 @@ func (s *deviceService) processAsyncFilterAndAdd(ctx context.Context) {
 							ProfileName:    pw.DiscoveredDevice.ProfileName,
 							Protocols:      d.Protocols,
 							Labels:         d.Labels,
-							ServiceName:    pw.DiscoveredDevice.ServiceName,
+							ServiceName:    s.serviceKey,
 							AdminState:     pw.DiscoveredDevice.AdminState,
 							OperatingState: models.Up,
 							AutoEvents:     pw.DiscoveredDevice.AutoEvents,
diff --git a/pkg/service/init.go b/pkg/service/init.go
index 6f66cc7c..77f6444b 100644
--- a/pkg/service/init.go
+++ b/pkg/service/init.go
@@ -48,7 +48,7 @@ func (b *Bootstrap) BootstrapHandler(ctx context.Context, wg *sync.WaitGroup, _
 	s.controller = http.NewRestController(b.router, dic, s.serviceKey)
 	s.controller.InitRestRoutes()
 
-	edgexErr := cache.InitCache(s.serviceKey, dic)
+	edgexErr := cache.InitCache(s.serviceKey, s.baseServiceName, dic)
 	if edgexErr != nil {
 		s.lc.Errorf("Failed to init cache: %s", edgexErr.Error())
 		return false
@@ -110,7 +110,17 @@ func (b *Bootstrap) BootstrapHandler(ctx context.Context, wg *sync.WaitGroup, _
 	return true
 }
 
-func messageBusBootstrapHandler(ctx context.Context, wg *sync.WaitGroup, startupTimer startup.Timer, dic *di.Container) bool {
+func newMessageBusBootstrap(baseServiceName string) *messageBusBootstrap {
+	return &messageBusBootstrap{
+		baseServiceName: baseServiceName,
+	}
+}
+
+type messageBusBootstrap struct {
+	baseServiceName string
+}
+
+func (h *messageBusBootstrap) messageBusBootstrapHandler(ctx context.Context, wg *sync.WaitGroup, startupTimer startup.Timer, dic *di.Container) bool {
 	if !handlers.MessagingBootstrapHandler(ctx, wg, startupTimer, dic) {
 		return false
 	}
@@ -122,7 +132,7 @@ func messageBusBootstrapHandler(ctx context.Context, wg *sync.WaitGroup, startup
 		return false
 	}
 
-	err = messaging.MetadataSystemEventsCallback(ctx, dic)
+	err = messaging.MetadataSystemEventsCallback(ctx, h.baseServiceName, dic)
 	if err != nil {
 		lc.Errorf("Failed to subscribe Metadata system events: %v", err)
 		return false
diff --git a/pkg/service/service.go b/pkg/service/service.go
index f3cfbdc3..5286928d 100644
--- a/pkg/service/service.go
+++ b/pkg/service/service.go
@@ -53,6 +53,7 @@ const EnvInstanceName = "EDGEX_INSTANCE_NAME"
 
 type deviceService struct {
 	serviceKey         string
+	baseServiceName    string
 	lc                 logger.LoggingClient
 	driver             interfaces.ProtocolDriver
 	autoEventManager   interfaces.AutoEventManager
@@ -132,7 +133,7 @@ func (s *deviceService) Run() error {
 		bootstrapTypes.ServiceTypeDevice,
 		[]bootstrapInterfaces.BootstrapHandler{
 			httpServer.BootstrapHandler,
-			messageBusBootstrapHandler,
+			newMessageBusBootstrap(s.baseServiceName).messageBusBootstrapHandler,
 			handlers.NewServiceMetrics(s.serviceKey).BootstrapHandler, // Must be after Messaging
 			handlers.NewClientsBootstrap(s.flags.InDevMode()).BootstrapHandler,
 			autoevent.BootstrapHandler,
@@ -307,6 +308,9 @@ func (s *deviceService) setServiceName(instanceName string) {
 		instanceName = envValue
 	}
 
+	// Need to capture the base service name to use when loading Provision Watchers so that all instances find the defined provision watchers.
+	s.baseServiceName = s.serviceKey
+
 	if len(instanceName) > 0 {
 		s.serviceKey = s.serviceKey + "_" + instanceName
 	}


Test patch:
diff --git a/internal/common/utils_test.go b/internal/common/utils_test.go
index 8978e6f2..a6d7a5cd 100644
--- a/internal/common/utils_test.go
+++ b/internal/common/utils_test.go
@@ -265,7 +265,7 @@ func TestInitializeSentMetrics(t *testing.T) {
 
 func TestAddReadingTags(t *testing.T) {
 	dic := NewMockDIC()
-	edgexErr := cache.InitCache(TestDeviceService, dic)
+	edgexErr := cache.InitCache(TestDeviceService, TestDeviceService, dic)
 	require.NoError(t, edgexErr)
 	readingWithTags, err := dtos.NewSimpleReading(TestProfile, TestDeviceWithTags, TestDeviceResourceWithTags, common.ValueTypeString, "")
 	require.NoError(t, err)
@@ -299,7 +299,7 @@ func TestAddReadingTags(t *testing.T) {
 
 func TestAddEventTags(t *testing.T) {
 	dic := NewMockDIC()
-	edgexErr := cache.InitCache(TestDeviceService, dic)
+	edgexErr := cache.InitCache(TestDeviceService, TestDeviceService, dic)
 	require.NoError(t, edgexErr)
 
 	expectedDeviceTags := dtos.Tags{TestDeviceTagName: TestDeviceTagValue, TestDuplicateTagName: TestDeviceTagValue}
diff --git a/internal/controller/http/command_test.go b/internal/controller/http/command_test.go
index 9e72fbb9..5523af6a 100644
--- a/internal/controller/http/command_test.go
+++ b/internal/controller/http/command_test.go
@@ -206,7 +206,7 @@ func mockDic() *di.Container {
 func TestRestController_GetCommand(t *testing.T) {
 	dic := mockDic()
 
-	err := cache.InitCache(testService, dic)
+	err := cache.InitCache(testService, testService, dic)
 	require.NoError(t, err)
 
 	controller := NewRestController(mux.NewRouter(), dic, testService)
@@ -271,7 +271,7 @@ func TestRestController_GetCommand_ServiceLocked(t *testing.T) {
 		},
 	})
 
-	edgexErr := cache.InitCache(testService, dic)
+	edgexErr := cache.InitCache(testService, testService, dic)
 	require.NoError(t, edgexErr)
 
 	controller := NewRestController(mux.NewRouter(), dic, testService)
@@ -300,7 +300,7 @@ func TestRestController_GetCommand_ServiceLocked(t *testing.T) {
 func TestRestController_GetCommand_ReturnEvent(t *testing.T) {
 	dic := mockDic()
 
-	edgexErr := cache.InitCache(testService, dic)
+	edgexErr := cache.InitCache(testService, testService, dic)
 	require.NoError(t, edgexErr)
 
 	controller := NewRestController(mux.NewRouter(), dic, testService)
@@ -331,7 +331,7 @@ func TestRestController_SetCommand(t *testing.T) {
 	dic := mockDic()
 
 	sdkCommon.InitializeSentMetrics(logger.NewMockClient(), dic)
-	err := cache.InitCache(testService, dic)
+	err := cache.InitCache(testService, testService, dic)
 	require.NoError(t, err)
 
 	controller := NewRestController(mux.NewRouter(), dic, testService)
@@ -427,7 +427,7 @@ func TestRestController_SetCommand_ServiceLocked(t *testing.T) {
 	})
 	validRequest := map[string]any{testResource: "value"}
 
-	edgexErr := cache.InitCache(testService, dic)
+	edgexErr := cache.InitCache(testService, testService, dic)
 	require.NoError(t, edgexErr)
 
 	controller := NewRestController(mux.NewRouter(), dic, testService)
diff --git a/internal/transformer/transform_test.go b/internal/transformer/transform_test.go
index 47a77bc6..cccddcbb 100644
--- a/internal/transformer/transform_test.go
+++ b/internal/transformer/transform_test.go
@@ -144,7 +144,7 @@ func Test_getUniqueOrigin(t *testing.T) {
 
 func TestCommandValuesToEventDTO_ReadingUnits(t *testing.T) {
 	dic := NewMockDIC()
-	err := cache.InitCache(TestDeviceService, dic)
+	err := cache.InitCache(TestDeviceService, TestDeviceService, dic)
 	require.NoError(t, err)
 
 	stringCommandValue, e := sdkModels.NewCommandValue(TestDeviceResource, common.ValueTypeString, TestValue)