diff --git a/CHANGELOG.md b/CHANGELOG.md index 599ce3e586..5c9b64d078 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ For details about compatibility between different releases, see the **Commitment ### Changed +- Rate limiting for downlink queue operations (`DownlinkQueuePush`, `DownlinkQueueReplace`) is now applied at the application level instead of per-device. This may result in more `ResourceExhausted` (429) errors when multiple devices under the same application perform downlink queue operations concurrently. + ### Deprecated ### Removed diff --git a/pkg/ttnpb/application_interfaces.go b/pkg/ttnpb/application_interfaces.go index 45c34e305d..c80a4c58b7 100644 --- a/pkg/ttnpb/application_interfaces.go +++ b/pkg/ttnpb/application_interfaces.go @@ -210,3 +210,13 @@ func (m *DownlinkQueueRequest) IDString() string { } return ids.IDString() } + +// RateLimitKey implements ratelimit.Keyer. +// Returns an application-level key to enable rate limiting per application for downlink queue operations. +func (m *DownlinkQueueRequest) RateLimitKey() string { + ids := m.EndDeviceIds + if ids == nil { + return "" + } + return "application:" + ids.GetApplicationIds().IDString() +}