Skip to content
2 changes: 2 additions & 0 deletions pkg/common/bizerror/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const (
NacosError ErrorCode = "NacosError"
ZKError ErrorCode = "ZKError"
EventError ErrorCode = "EventError"
LockNotHeld ErrorCode = "LockNotHeld"
LockExpired ErrorCode = "LockExpired"
GovernorError ErrorCode = "GovernorError"
JsonError ErrorCode = "JsonError"
YamlError ErrorCode = "YamlError"
Expand Down
57 changes: 57 additions & 0 deletions pkg/common/constants/lock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package constants

import "time"

const (
// DefaultLockTimeout is the default timeout for distributed lock operations
// This timeout applies to lock acquisition, renewal, and release operations
DefaultLockTimeout = 30 * time.Second

// DefaultAutoRenewThreshold is the TTL threshold above which auto-renewal is enabled
// Locks with TTL longer than this value will be automatically renewed
DefaultAutoRenewThreshold = 10 * time.Second

// DefaultUnlockTimeout is the timeout for unlock operations in deferred cleanup
DefaultUnlockTimeout = 5 * time.Second

// DefaultRenewTimeout is the timeout for lock renewal operations
DefaultRenewTimeout = 5 * time.Second

// DefaultLockRetryInterval is the interval between lock acquisition retry attempts
DefaultLockRetryInterval = 100 * time.Millisecond

// DefaultCleanupInterval is the interval for periodic expired lock cleanup
DefaultCleanupInterval = 5 * time.Minute

// DefaultCleanupTimeout is the timeout for cleanup operations
DefaultCleanupTimeout = 30 * time.Second
)

// Lock key prefixes for different resource types
const (
// TagRouteKeyPrefix is the prefix for tag route lock keys
TagRouteKeyPrefix = "tag_route"

// ConfiguratorRuleKeyPrefix is the prefix for configurator rule lock keys
ConfiguratorRuleKeyPrefix = "configurator_rule"

// ConditionRuleKeyPrefix is the prefix for condition rule lock keys
ConditionRuleKeyPrefix = "condition_rule"
)
10 changes: 10 additions & 0 deletions pkg/console/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ import (

"github.com/apache/dubbo-admin/pkg/config/app"
"github.com/apache/dubbo-admin/pkg/console/counter"
"github.com/apache/dubbo-admin/pkg/core/lock"
"github.com/apache/dubbo-admin/pkg/core/manager"
"github.com/apache/dubbo-admin/pkg/core/runtime"
)

type Context interface {
ResourceManager() manager.ResourceManager
CounterManager() counter.CounterManager
LockManager() lock.Lock

Config() app.AdminConfig

Expand Down Expand Up @@ -71,3 +73,11 @@ func (c *context) CounterManager() counter.CounterManager {
}
return managerComp.CounterManager()
}

func (c *context) LockManager() lock.Lock {
distributedLock, err := lock.GetLockFromRuntime(c.coreRt)
if err != nil {
return nil
}
return distributedLock
}
52 changes: 51 additions & 1 deletion pkg/console/service/condition_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
package service

import (
"fmt"
"time"

"github.com/duke-git/lancet/v2/slice"
"github.com/duke-git/lancet/v2/strutil"

Expand Down Expand Up @@ -105,7 +108,24 @@
return res, nil
}

func UpdateConditionRule(ctx context.Context, name string, res *meshresource.ConditionRouteResource) error {
lock := ctx.LockManager()
if lock == nil {
// Lock not available, proceed without lock protection
return updateConditionRuleUnsafe(ctx, name, res)
}

// Use distributed lock to prevent concurrent modifications
lockKey := fmt.Sprintf("condition_route:%s:%s", res.Mesh, name)
lockTimeout := 30 * time.Second

return lock.WithLock(ctx.AppContext(), lockKey, lockTimeout, func() error {
return updateConditionRuleUnsafe(ctx, name, res)
})
}

func updateConditionRuleUnsafe(ctx context.Context, name string, res *meshresource.ConditionRouteResource) error {
func UpdateConditionRule(ctx context.Context, res *meshresource.ConditionRouteResource) error {

Check failure on line 128 in pkg/console/service/condition_rule.go

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest - Go 1.23)

expected '(', found UpdateConditionRule
if err := ctx.ResourceManager().Update(res); err != nil {
logger.Warnf("update %s condition failed with error: %s", res.Name, err.Error())
return err
Expand All @@ -113,7 +133,22 @@
return nil
}


func CreateConditionRule(ctx context.Context, name string, res *meshresource.ConditionRouteResource) error {

Check failure on line 137 in pkg/console/service/condition_rule.go

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest - Go 1.23)

expected '(', found CreateConditionRule
lock := ctx.LockManager()
if lock == nil {
return createConditionRuleUnsafe(ctx, name, res)
}

lockKey := fmt.Sprintf("condition_route:%s:%s", res.Mesh, name)
lockTimeout := 30 * time.Second

return lock.WithLock(ctx.AppContext(), lockKey, lockTimeout, func() error {
return createConditionRuleUnsafe(ctx, name, res)
})
}

func CreateConditionRule(ctx context.Context, res *meshresource.ConditionRouteResource) error {

Check failure on line 151 in pkg/console/service/condition_rule.go

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest - Go 1.23)

expected '(', found CreateConditionRule
if err := ctx.ResourceManager().Add(res); err != nil {
logger.Warnf("create %s condition failed with error: %s", res.Name, err.Error())
return err
Expand All @@ -121,9 +156,24 @@
return nil
}

func DeleteConditionRule(ctx context.Context, name string, mesh string) error {

Check failure on line 159 in pkg/console/service/condition_rule.go

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest - Go 1.23)

expected '(', found DeleteConditionRule
lock := ctx.LockManager()
if lock == nil {
return ctx.ResourceManager().DeleteByKey(meshresource.ConditionRouteKind, coremodel.BuildResourceKey(mesh, name))

if err := ctx.ResourceManager().DeleteByKey(meshresource.ConditionRouteKind, mesh, coremodel.BuildResourceKey(mesh, name)); err != nil {
return err
}
return nil

lockKey := fmt.Sprintf("condition_route:%s:%s", mesh, name)
lockTimeout := 30 * time.Second

return lock.WithLock(ctx.AppContext(), lockKey, lockTimeout, func() error {
err := ctx.ResourceManager().DeleteByKey(meshresource.ConditionRouteKind, coremodel.BuildResourceKey(mesh, name))
if err != nil {
logger.Warnf("delete %s condition failed with error: %s", name, err.Error())
return err
}
return nil
})
}

Check failure on line 179 in pkg/console/service/condition_rule.go

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest - Go 1.23)

expected '}', found 'EOF'
47 changes: 46 additions & 1 deletion pkg/console/service/configurator_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
package service

import (
"fmt"
"time"

"github.com/duke-git/lancet/v2/slice"

"github.com/apache/dubbo-admin/pkg/common/bizerror"
Expand Down Expand Up @@ -113,6 +116,20 @@
return res, nil
}

func UpdateConfigurator(ctx consolectx.Context, name string, res *meshresource.DynamicConfigResource) error {
lock := ctx.LockManager()
if lock == nil {
return updateConfiguratorUnsafe(ctx, name, res)
}

lockKey := fmt.Sprintf("dynamic_config:%s:%s", res.Mesh, name)
lockTimeout := 30 * time.Second

return lock.WithLock(ctx.AppContext(), lockKey, lockTimeout, func() error {
return updateConfiguratorUnsafe(ctx, name, res)
})
}

func UpdateConfigurator(ctx consolectx.Context, res *meshresource.DynamicConfigResource) error {
if err := ctx.ResourceManager().Update(res); err != nil {
logger.Warnf("update %s configurator failed with error: %s", res.Name, err.Error())
Expand All @@ -121,6 +138,20 @@
return nil
}

func CreateConfigurator(ctx consolectx.Context, name string, res *meshresource.DynamicConfigResource) error {
lock := ctx.LockManager()
if lock == nil {
return createConfiguratorUnsafe(ctx, name, res)
}

lockKey := fmt.Sprintf("dynamic_config:%s:%s", res.Mesh, name)
lockTimeout := 30 * time.Second

return lock.WithLock(ctx.AppContext(), lockKey, lockTimeout, func() error {
return createConfiguratorUnsafe(ctx, name, res)
})
}

func CreateConfigurator(ctx consolectx.Context, res *meshresource.DynamicConfigResource) error {
if err := ctx.ResourceManager().Add(res); err != nil {
logger.Warnf("create %s configurator failed with error: %s", res.Name, err.Error())
Expand All @@ -130,9 +161,23 @@
}

func DeleteConfigurator(ctx consolectx.Context, name string, mesh string) error {
lock := ctx.LockManager()
if lock == nil {
return ctx.ResourceManager().DeleteByKey(meshresource.DynamicConfigKind, coremodel.BuildResourceKey(mesh, name))

if err := ctx.ResourceManager().DeleteByKey(meshresource.DynamicConfigKind, mesh, coremodel.BuildResourceKey(mesh, name)); err != nil {
logger.Warnf("delete %s configurator failed with error: %s", name, err.Error())
return err
}
return nil

lockKey := fmt.Sprintf("dynamic_config:%s:%s", mesh, name)
lockTimeout := 30 * time.Second

return lock.WithLock(ctx.AppContext(), lockKey, lockTimeout, func() error {
if err := ctx.ResourceManager().DeleteByKey(meshresource.DynamicConfigKind, coremodel.BuildResourceKey(mesh, name)); err != nil {
logger.Warnf("delete %s configurator failed with error: %s", name, err.Error())
return err
}
return nil
})
}

Check failure on line 183 in pkg/console/service/configurator_rule.go

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest - Go 1.23)

expected '}', found 'EOF'
45 changes: 44 additions & 1 deletion pkg/console/service/tag_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
package service

import (
"github.com/apache/dubbo-admin/pkg/common/constants"
consolectx "github.com/apache/dubbo-admin/pkg/console/context"
"github.com/apache/dubbo-admin/pkg/core/lock"
"github.com/duke-git/lancet/v2/slice"

"github.com/apache/dubbo-admin/pkg/common/bizerror"
Expand Down Expand Up @@ -112,6 +115,19 @@
}

func UpdateTagRule(ctx consolectx.Context, res *meshresource.TagRouteResource) error {
lockMgr := ctx.LockManager()
if lockMgr == nil {
return updateTagRuleUnsafe(ctx, res)
}

lockKey := lock.BuildTagRouteLockKey(res.Mesh, res.Name)

return lockMgr.WithLock(ctx.AppContext(), lockKey, constants.DefaultLockTimeout, func() error {
return updateTagRuleUnsafe(ctx, res)
})
}

func updateTagRuleUnsafe(ctx consolectx.Context, res *meshresource.TagRouteResource) error {
err := ctx.ResourceManager().Update(res)
if err != nil {
logger.Warnf("update tag rule %s error: %v", res.Name, err)
Expand All @@ -121,6 +137,19 @@
}

func CreateTagRule(ctx consolectx.Context, res *meshresource.TagRouteResource) error {
lockMgr := ctx.LockManager()
if lockMgr == nil {
return createTagRuleUnsafe(ctx, res)
}

lockKey := lock.BuildTagRouteLockKey(res.Mesh, res.Name)

return lockMgr.WithLock(ctx.AppContext(), lockKey, constants.DefaultLockTimeout, func() error {
return createTagRuleUnsafe(ctx, res)
})
}

func createTagRuleUnsafe(ctx consolectx.Context, res *meshresource.TagRouteResource) error {
err := ctx.ResourceManager().Add(res)
if err != nil {
logger.Warnf("create tag rule %s error: %v", res.Name, err)
Expand All @@ -130,10 +159,24 @@
}

func DeleteTagRule(ctx consolectx.Context, name string, mesh string) error {
lockMgr := ctx.LockManager()
if lockMgr == nil {
return ctx.ResourceManager().DeleteByKey(meshresource.TagRouteKind, coremodel.BuildResourceKey(mesh, name))

err := ctx.ResourceManager().DeleteByKey(meshresource.TagRouteKind, mesh, coremodel.BuildResourceKey(mesh, name))
if err != nil {
logger.Warnf("delete tag rule %s error: %v", name, err)
return err
}
return nil

lockKey := lock.BuildTagRouteLockKey(mesh, name)

return lockMgr.WithLock(ctx.AppContext(), lockKey, constants.DefaultLockTimeout, func() error {
err := ctx.ResourceManager().DeleteByKey(meshresource.TagRouteKind, coremodel.BuildResourceKey(mesh, name))
if err != nil {
logger.Warnf("delete tag rule %s error: %v", name, err)
return err
}
return nil
})
}

Check failure on line 182 in pkg/console/service/tag_rule.go

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest - Go 1.23)

expected '}', found 'EOF'
Loading
Loading