code.gitea.io/gitea@v1.22.3/modules/queue/queue.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 // Package queue implements a specialized concurrent queue system for Gitea. 5 // 6 // Terminology: 7 // 8 // 1. Item: 9 // - An item can be a simple value, such as an integer, or a more complex structure that has multiple fields. 10 // Usually a item serves as a task or a message. Sets of items will be sent to a queue handler to be processed. 11 // - It's represented as a JSON-marshaled binary slice in the queue 12 // - Since the item is marshaled by JSON, and JSON doesn't have stable key-order/type support, 13 // so the decoded handler item may not be the same as the original "pushed" one if you use map/any types, 14 // 15 // 2. Batch: 16 // - A collection of items that are grouped together for processing. Each worker receives a batch of items. 17 // 18 // 3. Worker: 19 // - Individual unit of execution designed to process items from the queue. It's a goroutine that calls the Handler. 20 // - Workers will get new items through a channel (WorkerPoolQueue is responsible for the distribution). 21 // - Workers operate in parallel. The default value of max workers is determined by the setting system. 22 // 23 // 4. Handler (represented by HandlerFuncT type): 24 // - It's the function responsible for processing items. Each active worker will call it. 25 // - If an item or some items are not psuccessfully rocessed, the handler could return them as "unhandled items". 26 // In such scenarios, the queue system ensures these unhandled items are returned to the base queue after a brief delay. 27 // This mechanism is particularly beneficial in cases where the processing entity (like a document indexer) is 28 // temporarily unavailable. It ensures that no item is skipped or lost due to transient failures in the processing 29 // mechanism. 30 // 31 // 5. Base queue: 32 // - Represents the underlying storage mechanism for the queue. There are several implementations: 33 // - Channel: Uses Go's native channel constructs to manage the queue, suitable for in-memory queuing. 34 // - LevelDB: Especially useful in persistent queues for single instances. 35 // - Redis: Suitable for clusters, where we may have multiple nodes. 36 // - Dummy: This is special, it's not a real queue, it's a immediate no-op queue, which is useful for tests. 37 // - They all have the same abstraction, the same interface, and they are tested by the same testing code. 38 // 39 // 6. WorkerPoolQueue: 40 // - It's responsible to glue all together, using the "base queue" to provide "worker pool" functionality. It creates 41 // new workers if needed and can flush the queue, running all the items synchronously till it finishes. 42 // - Its "Push" function doesn't block forever, it will return an error if the queue is full after the timeout. 43 // 44 // 7. Manager: 45 // - The purpose of it is to serve as a centralized manager for multiple WorkerPoolQueue instances. Whenever we want 46 // to create a new queue, flush, or get a specific queue, we could use it. 47 // 48 // A queue can be "simple" or "unique". A unique queue will try to avoid duplicate items. 49 // Unique queue's "Has" function can be used to check whether an item is already in the queue, 50 // although it's not 100% reliable due to the lack of proper transaction support. 51 // Simple queue's "Has" function always returns "has=false". 52 // 53 // A WorkerPoolQueue is a generic struct; this means it will work with any type but just for that type. 54 // If you want another kind of items to run, you would have to call the manager to create a new WorkerPoolQueue for you 55 // with a different handler that works with this new type of item. As an example of this: 56 // 57 // func Init() error { 58 // itemQueue = queue.CreateSimpleQueue(graceful.GetManager().ShutdownContext(), "queue-name", handler) 59 // ... 60 // } 61 // func handler(items ...*mypkg.QueueItem) []*mypkg.QueueItem { ... } 62 package queue 63 64 import "code.gitea.io/gitea/modules/util" 65 66 type HandlerFuncT[T any] func(...T) (unhandled []T) 67 68 var ErrAlreadyInQueue = util.NewAlreadyExistErrorf("already in queue")