blob: 11814d28a40783cd8967fcf71a8965f9e0e1624f [file]
/*
* 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 lock
import (
"context"
"math"
"time"
"github.com/pkg/errors"
"github.com/apache/dubbo-admin/pkg/common/constants"
"github.com/apache/dubbo-admin/pkg/core/logger"
"github.com/apache/dubbo-admin/pkg/core/runtime"
)
func init() {
runtime.RegisterComponent(NewComponent())
}
const (
// DistributedLockComponent is the component type for distributed lock
DistributedLockComponent runtime.ComponentType = "distributed lock"
)
// Component implements the runtime.Component interface for distributed lock
type Component struct {
lock Lock
}
// NewComponent creates a new distributed lock component
func NewComponent() *Component {
return &Component{}
}
// Type returns the component type
func (c *Component) Type() runtime.ComponentType {
return DistributedLockComponent
}
// Order indicates the initialization order
// Lock should be initialized after Store (Order math.MaxInt - 1)
// Higher order values are initialized first, so we use math.MaxInt - 2
func (c *Component) Order() int {
return math.MaxInt - 2 // After Store, before other services
}
// Init initializes the distributed lock component
func (c *Component) Init(ctx runtime.BuilderContext) error {
factory, err := LockFactoryRegistry().GetSupportedFactory(ctx)
if err != nil {
// No supporting factory found
logger.Warnf("No supported lock factory found: %v", err)
logger.Warn("Distributed lock will not be available")
return nil
}
// Lock created using a factory
lock, err := factory.NewLock(ctx)
if err != nil {
return errors.Wrap(err, "failed to create distributed lock")
}
c.lock = lock
logger.Info("Distributed lock component initialized successfully")
return nil
}
// Start starts the distributed lock component
func (c *Component) Start(rt runtime.Runtime, stop <-chan struct{}) error {
if c.lock == nil {
logger.Warn("Distributed lock not available, skipping")
return nil
}
// Start background cleanup task
ticker := time.NewTicker(constants.DefaultCleanupInterval) // Cleanup every 5 minutes
defer ticker.Stop()
for {
select {
case <-stop:
return nil
case <-ticker.C:
ctx, cancel := context.WithTimeout(context.Background(), constants.DefaultCleanupTimeout)
if err := c.lock.CleanupExpiredLocks(ctx); err != nil {
logger.Errorf("Failed to cleanup expired locks: %v", err)
}
cancel()
}
}
}
// GetLock returns the lock instance
func (c *Component) GetLock() Lock {
return c.lock
}
// GetLockFromRuntime extracts the lock instance from runtime
func GetLockFromRuntime(rt runtime.Runtime) (Lock, error) {
comp, err := rt.GetComponent(DistributedLockComponent)
if err != nil {
return nil, err
}
lockComp, ok := comp.(*Component)
if !ok {
return nil, errors.Errorf("component %s is not a valid lock component", DistributedLockComponent)
}
if lockComp.lock == nil {
return nil, errors.New("distributed lock is not available (possibly using memory store)")
}
return lockComp.GetLock(), nil
}
func (c *Component) RequiredDependencies() []runtime.ComponentType {
return []runtime.ComponentType{
runtime.ResourceStore,
}
}