go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/tq/internal/lessor/lessor.go (about)

     1  // Copyright 2020 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package lessor defines common lessor interface.
    16  package lessor
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"time"
    22  
    23  	"go.chromium.org/luci/common/errors"
    24  
    25  	"go.chromium.org/luci/server/tq/internal/partition"
    26  )
    27  
    28  // WithLeaseCB executes with active lease on the provided SortedPartitions.
    29  //
    30  // SortedPartitions may be empty slice, meaning there were existing active
    31  // leases cumulatively covering the entire desired partition.
    32  // Context deadline is set before the lease expires.
    33  type WithLeaseCB func(context.Context, partition.SortedPartitions)
    34  
    35  // Lessor abstracts out different implementations aimed to prevent concurrent
    36  // processing of the same range of Reminders.
    37  //
    38  // Lessors are used by the distributed sweep implementation.
    39  type Lessor interface {
    40  	// WithLease acquires the lease and executes WithLeaseCB.
    41  	//
    42  	// The obtained lease duration may be shorter than requested.
    43  	// The obtained lease may be only for some parts of the desired Partition.
    44  	//
    45  	// The given `sectionID` identifies a transactionally updated object that
    46  	// actually stores records about the currently leased sub-partitions of
    47  	// `part`. Each such section is independent of another. In other words, if
    48  	// some range of keys is covered by two different sections, it may be leased
    49  	// to two different callers at the same time, there's no synchronization in
    50  	// such case.
    51  	WithLease(ctx context.Context, sectionID string, part *partition.Partition, dur time.Duration, cb WithLeaseCB) error
    52  }
    53  
    54  var lessors = map[string]func(ctx context.Context) (Lessor, error){}
    55  
    56  // Register registers a lessor implementation.
    57  //
    58  // Preferably IDs should match the corresponding database.Database
    59  // implementations, since by default if the TQ uses a database "<X>" it will use
    60  // the lessor "<X>" as well. But there may be IDs that are no associated with
    61  // any database implementation (e.g. a Redis-based lessor). Such lessors need
    62  // an explicit opt-in to be used.
    63  //
    64  // Must be called during init time.
    65  func Register(id string, factory func(ctx context.Context) (Lessor, error)) {
    66  	if lessors[id] != nil {
    67  		panic(fmt.Sprintf("lessor kind %q is already registered", id))
    68  	}
    69  	lessors[id] = factory
    70  }
    71  
    72  // Get returns a particular Lessor implementation given its ID.
    73  func Get(ctx context.Context, id string) (Lessor, error) {
    74  	if factory := lessors[id]; factory != nil {
    75  		return factory(ctx)
    76  	}
    77  	return nil, errors.Reason("no lessor kind %q is registered in the process", id).Err()
    78  }