You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

queue.go 3.8KB

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