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 }