2020-01-07 11:23:09 +00:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 18:20:29 +00:00
// SPDX-License-Identifier: MIT
2020-01-07 11:23:09 +00:00
package setting
import (
2020-01-08 14:30:58 +00:00
"path/filepath"
2021-10-17 11:43:25 +00:00
"strconv"
2020-01-07 11:23:09 +00:00
"time"
2022-10-12 05:18:26 +00:00
"code.gitea.io/gitea/modules/container"
2020-01-07 11:23:09 +00:00
"code.gitea.io/gitea/modules/log"
2021-11-17 12:34:35 +00:00
2021-10-17 11:43:25 +00:00
ini "gopkg.in/ini.v1"
2020-01-07 11:23:09 +00:00
)
// QueueSettings represent the settings for a queue from the ini
type QueueSettings struct {
2020-10-15 21:40:03 +00:00
Name string
2020-01-07 11:23:09 +00:00
DataDir string
2020-10-15 21:40:03 +00:00
QueueLength int ` ini:"LENGTH" `
2020-01-07 11:23:09 +00:00
BatchLength int
ConnectionString string
Type string
QueueName string
2020-02-02 23:19:58 +00:00
SetName string
2020-01-07 11:23:09 +00:00
WrapIfNecessary bool
MaxAttempts int
Timeout time . Duration
Workers int
MaxWorkers int
BlockTimeout time . Duration
BoostTimeout time . Duration
BoostWorkers int
}
// Queue settings
var Queue = QueueSettings { }
// GetQueueSettings returns the queue settings for the appropriately named queue
func GetQueueSettings ( name string ) QueueSettings {
2023-02-19 16:12:01 +00:00
return getQueueSettings ( CfgProvider , name )
}
func getQueueSettings ( rootCfg ConfigProvider , name string ) QueueSettings {
2020-01-07 11:23:09 +00:00
q := QueueSettings { }
2023-02-19 16:12:01 +00:00
sec := rootCfg . Section ( "queue." + name )
2020-10-15 21:40:03 +00:00
q . Name = name
2020-01-07 11:23:09 +00:00
// DataDir is not directly inheritable
2021-05-26 02:50:35 +00:00
q . DataDir = filepath . ToSlash ( filepath . Join ( Queue . DataDir , "common" ) )
2020-01-07 11:23:09 +00:00
// QueueName is not directly inheritable either
q . QueueName = name + Queue . QueueName
for _ , key := range sec . Keys ( ) {
switch key . Name ( ) {
case "DATADIR" :
q . DataDir = key . MustString ( q . DataDir )
case "QUEUE_NAME" :
q . QueueName = key . MustString ( q . QueueName )
2020-02-02 23:19:58 +00:00
case "SET_NAME" :
q . SetName = key . MustString ( q . SetName )
2020-01-07 11:23:09 +00:00
}
}
2020-02-02 23:19:58 +00:00
if len ( q . SetName ) == 0 && len ( Queue . SetName ) > 0 {
q . SetName = q . QueueName + Queue . SetName
}
2020-01-08 14:30:58 +00:00
if ! filepath . IsAbs ( q . DataDir ) {
2021-06-16 22:19:20 +00:00
q . DataDir = filepath . ToSlash ( filepath . Join ( AppDataPath , q . DataDir ) )
2020-01-07 11:23:09 +00:00
}
2020-01-29 01:01:06 +00:00
_ , _ = sec . NewKey ( "DATADIR" , q . DataDir )
2020-10-15 21:40:03 +00:00
2020-01-07 11:23:09 +00:00
// The rest are...
2020-10-15 21:40:03 +00:00
q . QueueLength = sec . Key ( "LENGTH" ) . MustInt ( Queue . QueueLength )
2020-01-07 11:23:09 +00:00
q . BatchLength = sec . Key ( "BATCH_LENGTH" ) . MustInt ( Queue . BatchLength )
q . ConnectionString = sec . Key ( "CONN_STR" ) . MustString ( Queue . ConnectionString )
q . Type = sec . Key ( "TYPE" ) . MustString ( Queue . Type )
q . WrapIfNecessary = sec . Key ( "WRAP_IF_NECESSARY" ) . MustBool ( Queue . WrapIfNecessary )
q . MaxAttempts = sec . Key ( "MAX_ATTEMPTS" ) . MustInt ( Queue . MaxAttempts )
q . Timeout = sec . Key ( "TIMEOUT" ) . MustDuration ( Queue . Timeout )
q . Workers = sec . Key ( "WORKERS" ) . MustInt ( Queue . Workers )
q . MaxWorkers = sec . Key ( "MAX_WORKERS" ) . MustInt ( Queue . MaxWorkers )
q . BlockTimeout = sec . Key ( "BLOCK_TIMEOUT" ) . MustDuration ( Queue . BlockTimeout )
q . BoostTimeout = sec . Key ( "BOOST_TIMEOUT" ) . MustDuration ( Queue . BoostTimeout )
q . BoostWorkers = sec . Key ( "BOOST_WORKERS" ) . MustInt ( Queue . BoostWorkers )
return q
}
2023-02-19 16:12:01 +00:00
// LoadQueueSettings sets up the default settings for Queues
2020-01-07 11:23:09 +00:00
// This is exported for tests to be able to use the queue
2023-02-19 16:12:01 +00:00
func LoadQueueSettings ( ) {
loadQueueFrom ( CfgProvider )
}
func loadQueueFrom ( rootCfg ConfigProvider ) {
sec := rootCfg . Section ( "queue" )
2021-05-26 02:50:35 +00:00
Queue . DataDir = filepath . ToSlash ( sec . Key ( "DATADIR" ) . MustString ( "queues/" ) )
2020-01-08 14:30:58 +00:00
if ! filepath . IsAbs ( Queue . DataDir ) {
2021-05-26 02:50:35 +00:00
Queue . DataDir = filepath . ToSlash ( filepath . Join ( AppDataPath , Queue . DataDir ) )
2020-01-07 11:23:09 +00:00
}
2020-10-15 21:40:03 +00:00
Queue . QueueLength = sec . Key ( "LENGTH" ) . MustInt ( 20 )
2020-01-07 11:23:09 +00:00
Queue . BatchLength = sec . Key ( "BATCH_LENGTH" ) . MustInt ( 20 )
2020-10-04 17:12:26 +00:00
Queue . ConnectionString = sec . Key ( "CONN_STR" ) . MustString ( "" )
2021-06-16 22:19:20 +00:00
defaultType := sec . Key ( "TYPE" ) . String ( )
2020-01-29 01:01:06 +00:00
Queue . Type = sec . Key ( "TYPE" ) . MustString ( "persistable-channel" )
2020-01-07 11:23:09 +00:00
Queue . WrapIfNecessary = sec . Key ( "WRAP_IF_NECESSARY" ) . MustBool ( true )
Queue . MaxAttempts = sec . Key ( "MAX_ATTEMPTS" ) . MustInt ( 10 )
Queue . Timeout = sec . Key ( "TIMEOUT" ) . MustDuration ( GracefulHammerTime + 30 * time . Second )
2021-05-23 23:23:55 +00:00
Queue . Workers = sec . Key ( "WORKERS" ) . MustInt ( 0 )
2020-01-07 11:23:09 +00:00
Queue . MaxWorkers = sec . Key ( "MAX_WORKERS" ) . MustInt ( 10 )
Queue . BlockTimeout = sec . Key ( "BLOCK_TIMEOUT" ) . MustDuration ( 1 * time . Second )
Queue . BoostTimeout = sec . Key ( "BOOST_TIMEOUT" ) . MustDuration ( 5 * time . Minute )
2021-05-23 23:23:55 +00:00
Queue . BoostWorkers = sec . Key ( "BOOST_WORKERS" ) . MustInt ( 1 )
2020-01-07 11:23:09 +00:00
Queue . QueueName = sec . Key ( "QUEUE_NAME" ) . MustString ( "_queue" )
2020-02-02 23:19:58 +00:00
Queue . SetName = sec . Key ( "SET_NAME" ) . MustString ( "" )
2020-01-07 11:23:09 +00:00
// Now handle the old issue_indexer configuration
2022-01-20 17:00:38 +00:00
// FIXME: DEPRECATED to be removed in v1.18.0
2023-02-19 16:12:01 +00:00
section := rootCfg . Section ( "queue.issue_indexer" )
2022-10-12 05:18:26 +00:00
directlySet := toDirectlySetKeysSet ( section )
if ! directlySet . Contains ( "TYPE" ) && defaultType == "" {
2023-02-19 16:12:01 +00:00
switch typ := rootCfg . Section ( "indexer" ) . Key ( "ISSUE_INDEXER_QUEUE_TYPE" ) . MustString ( "" ) ; typ {
2022-01-20 17:00:38 +00:00
case "levelqueue" :
2020-01-29 01:01:06 +00:00
_ , _ = section . NewKey ( "TYPE" , "level" )
2022-01-20 17:00:38 +00:00
case "channel" :
2020-01-29 01:01:06 +00:00
_ , _ = section . NewKey ( "TYPE" , "persistable-channel" )
2022-01-20 17:00:38 +00:00
case "redis" :
2020-01-29 01:01:06 +00:00
_ , _ = section . NewKey ( "TYPE" , "redis" )
2021-06-16 22:19:20 +00:00
case "" :
_ , _ = section . NewKey ( "TYPE" , "level" )
2020-01-07 11:23:09 +00:00
default :
2022-01-20 17:00:38 +00:00
log . Fatal ( "Unsupported indexer queue type: %v" , typ )
2020-01-07 11:23:09 +00:00
}
}
2022-10-12 05:18:26 +00:00
if ! directlySet . Contains ( "LENGTH" ) {
2023-02-19 16:12:01 +00:00
length := rootCfg . Section ( "indexer" ) . Key ( "UPDATE_BUFFER_LEN" ) . MustInt ( 0 )
2022-01-20 17:00:38 +00:00
if length != 0 {
_ , _ = section . NewKey ( "LENGTH" , strconv . Itoa ( length ) )
}
2020-01-07 11:23:09 +00:00
}
2022-10-12 05:18:26 +00:00
if ! directlySet . Contains ( "BATCH_LENGTH" ) {
2023-02-19 16:12:01 +00:00
fallback := rootCfg . Section ( "indexer" ) . Key ( "ISSUE_INDEXER_QUEUE_BATCH_NUMBER" ) . MustInt ( 0 )
2022-01-20 17:00:38 +00:00
if fallback != 0 {
_ , _ = section . NewKey ( "BATCH_LENGTH" , strconv . Itoa ( fallback ) )
}
2020-01-07 11:23:09 +00:00
}
2022-10-12 05:18:26 +00:00
if ! directlySet . Contains ( "DATADIR" ) {
2023-02-19 16:12:01 +00:00
queueDir := filepath . ToSlash ( rootCfg . Section ( "indexer" ) . Key ( "ISSUE_INDEXER_QUEUE_DIR" ) . MustString ( "" ) )
2022-01-20 17:00:38 +00:00
if queueDir != "" {
_ , _ = section . NewKey ( "DATADIR" , queueDir )
}
2020-01-07 11:23:09 +00:00
}
2022-10-12 05:18:26 +00:00
if ! directlySet . Contains ( "CONN_STR" ) {
2023-02-19 16:12:01 +00:00
connStr := rootCfg . Section ( "indexer" ) . Key ( "ISSUE_INDEXER_QUEUE_CONN_STR" ) . MustString ( "" )
2022-01-20 17:00:38 +00:00
if connStr != "" {
_ , _ = section . NewKey ( "CONN_STR" , connStr )
}
2020-01-07 11:23:09 +00:00
}
2020-01-16 17:55:36 +00:00
2022-01-20 17:00:38 +00:00
// FIXME: DEPRECATED to be removed in v1.18.0
// - will need to set default for [queue.*)] LENGTH appropriately though though
2020-01-16 17:55:36 +00:00
// Handle the old mailer configuration
2023-02-19 16:12:01 +00:00
handleOldLengthConfiguration ( rootCfg , "mailer" , "mailer" , "SEND_BUFFER_LEN" , 100 )
2020-02-02 23:19:58 +00:00
// Handle the old test pull requests configuration
// Please note this will be a unique queue
2023-02-19 16:12:01 +00:00
handleOldLengthConfiguration ( rootCfg , "pr_patch_checker" , "repository" , "PULL_REQUEST_QUEUE_LENGTH" , 1000 )
2021-10-17 11:43:25 +00:00
// Handle the old mirror queue configuration
// Please note this will be a unique queue
2023-02-19 16:12:01 +00:00
handleOldLengthConfiguration ( rootCfg , "mirror" , "repository" , "MIRROR_QUEUE_LENGTH" , 1000 )
2021-10-17 11:43:25 +00:00
}
// handleOldLengthConfiguration allows fallback to older configuration. `[queue.name]` `LENGTH` will override this configuration, but
// if that is left unset then we should fallback to the older configuration. (Except where the new length woul be <=0)
2023-02-19 16:12:01 +00:00
func handleOldLengthConfiguration ( rootCfg ConfigProvider , queueName , o ldSection , oldKey string , defaultValue int ) {
if rootCfg . Section ( oldSection ) . HasKey ( oldKey ) {
2022-01-20 17:00:38 +00:00
log . Error ( "Deprecated fallback for %s queue length `[%s]` `%s` present. Use `[queue.%s]` `LENGTH`. This will be removed in v1.18.0" , queueName , queueName , oldSection , oldKey )
}
2023-02-19 16:12:01 +00:00
value := rootCfg . Section ( oldSection ) . Key ( oldKey ) . MustInt ( defaultValue )
2022-01-20 17:00:38 +00:00
2021-10-17 11:43:25 +00:00
// Don't override with 0
if value <= 0 {
return
}
2023-02-19 16:12:01 +00:00
section := rootCfg . Section ( "queue." + queueName )
2022-10-12 05:18:26 +00:00
directlySet := toDirectlySetKeysSet ( section )
if ! directlySet . Contains ( "LENGTH" ) {
2021-10-17 11:43:25 +00:00
_ , _ = section . NewKey ( "LENGTH" , strconv . Itoa ( value ) )
}
}
2022-10-12 05:18:26 +00:00
// toDirectlySetKeysSet returns a set of keys directly set by this section
2021-10-17 11:43:25 +00:00
// Note: we cannot use section.HasKey(...) as that will immediately set the Key if a parent section has the Key
// but this section does not.
2022-10-12 05:18:26 +00:00
func toDirectlySetKeysSet ( section * ini . Section ) container . Set [ string ] {
sections := make ( container . Set [ string ] )
2020-02-02 23:19:58 +00:00
for _ , key := range section . Keys ( ) {
2022-10-12 05:18:26 +00:00
sections . Add ( key . Name ( ) )
2020-02-02 23:19:58 +00:00
}
2022-10-12 05:18:26 +00:00
return sections
2020-01-07 11:23:09 +00:00
}