github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/cd-service/pkg/repository/queue.go (about) 1 /*This file is part of kuberpult. 2 3 Kuberpult is free software: you can redistribute it and/or modify 4 it under the terms of the Expat(MIT) License as published by 5 the Free Software Foundation. 6 7 Kuberpult is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 MIT License for more details. 11 12 You should have received a copy of the MIT License 13 along with kuberpult. If not, see <https://directory.fsf.org/wiki/License:Expat>. 14 15 Copyright 2023 freiheit.com*/ 16 17 package repository 18 19 /** 20 This queue contains transformers. Do not confuse with the "queuedVersion" field in protobuf (api.proto). 21 The queue here is used because applying a change to git (pushing) takes some time. 22 Still, every request waits for the transformer AND push to finish (that's what the `result` channel is for in the "transformerBatch struct" below). 23 This queue improves the throughput when there are many parallel requests, because the "push" operation is done only once for multiple requests (a request here is essentially the same as a transformer). 24 Many parallel requests can happen in a CI with many microservices that all call the "release" endpoint almost at the same time. 25 This queue does not improve the latency, because each request still waits for the push to finish. 26 */ 27 28 import ( 29 "context" 30 "fmt" 31 "github.com/freiheit-com/kuberpult/pkg/logger" 32 "go.uber.org/zap" 33 ) 34 35 type queue struct { 36 transformerBatches chan transformerBatch 37 } 38 39 var ErrQueueFull error 40 41 type transformerBatch struct { 42 ctx context.Context 43 transformers []Transformer 44 result chan error 45 } 46 47 func (t *transformerBatch) finish(err error) { 48 select { 49 case t.result <- err: 50 close(t.result) 51 default: 52 } 53 } 54 55 func (q *queue) add(ctx context.Context, transformers []Transformer) <-chan error { 56 resultChannel := make(chan error, 1) 57 e := transformerBatch{ 58 ctx: ctx, 59 transformers: transformers, 60 result: resultChannel, 61 } 62 63 select { 64 case q.transformerBatches <- e: 65 GaugeQueueSize(ctx, len(q.transformerBatches)) 66 return resultChannel 67 default: 68 //Channel is full, we don't want to put anything else there. 69 ErrQueueFull = fmt.Errorf("queue is full. Queue Capacity: %d.", cap(q.transformerBatches)) 70 e.finish(ErrQueueFull) 71 return resultChannel 72 } 73 } 74 75 func makeQueueN(size uint) queue { 76 return queue{ 77 transformerBatches: make(chan transformerBatch, size), 78 } 79 } 80 81 func GaugeQueueSize(ctx context.Context, queueSize int) { 82 if ddMetrics != nil { 83 err := ddMetrics.Gauge("request_queue_size", float64(queueSize), []string{}, 1) 84 85 if err != nil { 86 logger.FromContext(ctx).Error("Error gauging queue size metric: ", zap.Error(err)) 87 } 88 } 89 }