mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Rewrite queue (#24505)
# ⚠️ Breaking Many deprecated queue config options are removed (actually, they should have been removed in 1.18/1.19). If you see the fatal message when starting Gitea: "Please update your app.ini to remove deprecated config options", please follow the error messages to remove these options from your app.ini. Example: ``` 2023/05/06 19:39:22 [E] Removed queue option: `[indexer].ISSUE_INDEXER_QUEUE_TYPE`. Use new options in `[queue.issue_indexer]` 2023/05/06 19:39:22 [E] Removed queue option: `[indexer].UPDATE_BUFFER_LEN`. Use new options in `[queue.issue_indexer]` 2023/05/06 19:39:22 [F] Please update your app.ini to remove deprecated config options ``` Many options in `[queue]` are are dropped, including: `WRAP_IF_NECESSARY`, `MAX_ATTEMPTS`, `TIMEOUT`, `WORKERS`, `BLOCK_TIMEOUT`, `BOOST_TIMEOUT`, `BOOST_WORKERS`, they can be removed from app.ini. # The problem The old queue package has some legacy problems: * complexity: I doubt few people could tell how it works. * maintainability: Too many channels and mutex/cond are mixed together, too many different structs/interfaces depends each other. * stability: due to the complexity & maintainability, sometimes there are strange bugs and difficult to debug, and some code doesn't have test (indeed some code is difficult to test because a lot of things are mixed together). * general applicability: although it is called "queue", its behavior is not a well-known queue. * scalability: it doesn't seem easy to make it work with a cluster without breaking its behaviors. It came from some very old code to "avoid breaking", however, its technical debt is too heavy now. It's a good time to introduce a better "queue" package. # The new queue package It keeps using old config and concept as much as possible. * It only contains two major kinds of concepts: * The "base queue": channel, levelqueue, redis * They have the same abstraction, the same interface, and they are tested by the same testing code. * The "WokerPoolQueue", it uses the "base queue" to provide "worker pool" function, calls the "handler" to process the data in the base queue. * The new code doesn't do "PushBack" * Think about a queue with many workers, the "PushBack" can't guarantee the order for re-queued unhandled items, so in new code it just does "normal push" * The new code doesn't do "pause/resume" * The "pause/resume" was designed to handle some handler's failure: eg: document indexer (elasticsearch) is down * If a queue is paused for long time, either the producers blocks or the new items are dropped. * The new code doesn't do such "pause/resume" trick, it's not a common queue's behavior and it doesn't help much. * If there are unhandled items, the "push" function just blocks for a few seconds and then re-queue them and retry. * The new code doesn't do "worker booster" * Gitea's queue's handlers are light functions, the cost is only the go-routine, so it doesn't make sense to "boost" them. * The new code only use "max worker number" to limit the concurrent workers. * The new "Push" never blocks forever * Instead of creating more and more blocking goroutines, return an error is more friendly to the server and to the end user. There are more details in code comments: eg: the "Flush" problem, the strange "code.index" hanging problem, the "immediate" queue problem. Almost ready for review. TODO: * [x] add some necessary comments during review * [x] add some more tests if necessary * [x] update documents and config options * [x] test max worker / active worker * [x] re-run the CI tasks to see whether any test is flaky * [x] improve the `handleOldLengthConfiguration` to provide more friendly messages * [x] fine tune default config values (eg: length?) ## Code coverage: 
This commit is contained in:
@@ -1,36 +1,7 @@
|
||||
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin monitor")}}
|
||||
<div class="admin-setting-content">
|
||||
{{template "admin/cron" .}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queues"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<table class="ui very basic striped table unstackable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.name"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.type"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.exemplar"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.numberworkers"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.numberinqueue"}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Queues}}
|
||||
<tr>
|
||||
<td>{{.Name}}</td>
|
||||
<td>{{.Type}}</td>
|
||||
<td>{{.ExemplarType}}</td>
|
||||
<td>{{$sum := .NumberOfWorkers}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
||||
<td>{{$sum = .NumberInQueue}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
||||
<td><a href="{{$.Link}}/queue/{{.QID}}" class="button">{{if lt $sum 0}}{{$.locale.Tr "admin.monitor.queue.review"}}{{else}}{{$.locale.Tr "admin.monitor.queue.review_add"}}{{end}}</a>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{template "admin/queue" .}}
|
||||
{{template "admin/process" .}}
|
||||
</div>
|
||||
|
||||
|
@@ -1,192 +1,29 @@
|
||||
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin monitor")}}
|
||||
<div class="admin-setting-content">
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue" .Queue.Name}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<table class="ui very basic striped table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.name"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.type"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.exemplar"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.numberworkers"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.maxnumberworkers"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.numberinqueue"}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{.Queue.Name}}</td>
|
||||
<td>{{.Queue.Type}}</td>
|
||||
<td>{{.Queue.ExemplarType}}</td>
|
||||
<td>{{$sum := .Queue.NumberOfWorkers}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
||||
<td>{{if lt $sum 0}}-{{else}}{{.Queue.MaxNumberOfWorkers}}{{end}}</td>
|
||||
<td>{{$sum = .Queue.NumberInQueue}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{if lt $sum 0}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue.nopool.title"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
{{if eq .Queue.Type "wrapped"}}
|
||||
<p>{{.locale.Tr "admin.monitor.queue.wrapped.desc"}}</p>
|
||||
{{else if eq .Queue.Type "persistable-channel"}}
|
||||
<p>{{.locale.Tr "admin.monitor.queue.persistable-channel.desc"}}</p>
|
||||
{{else}}
|
||||
<p>{{.locale.Tr "admin.monitor.queue.nopool.desc"}}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue.settings.title"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p>{{.locale.Tr "admin.monitor.queue.settings.desc"}}</p>
|
||||
<form method="POST" action="{{.Link}}/set">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="ui form">
|
||||
<div class="inline field">
|
||||
<label for="max-number">{{.locale.Tr "admin.monitor.queue.settings.maxnumberworkers"}}</label>
|
||||
<input name="max-number" type="text" placeholder="{{.locale.Tr "admin.monitor.queue.settings.maxnumberworkers.placeholder" .Queue.MaxNumberOfWorkers}}">
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<label for="timeout">{{.locale.Tr "admin.monitor.queue.settings.timeout"}}</label>
|
||||
<input name="timeout" type="text" placeholder="{{.locale.Tr "admin.monitor.queue.settings.timeout.placeholder" .Queue.BoostTimeout}}">
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<label for="number">{{.locale.Tr "admin.monitor.queue.settings.numberworkers"}}</label>
|
||||
<input name="number" type="text" placeholder="{{.locale.Tr "admin.monitor.queue.settings.numberworkers.placeholder" .Queue.BoostWorkers}}">
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<label>{{.locale.Tr "admin.monitor.queue.settings.blocktimeout"}}</label>
|
||||
<span>{{.locale.Tr "admin.monitor.queue.settings.blocktimeout.value" .Queue.BlockTimeout}}</span>
|
||||
</div>
|
||||
<button class="ui submit button">{{.locale.Tr "admin.monitor.queue.settings.submit"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue.pool.addworkers.title"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p>{{.locale.Tr "admin.monitor.queue.pool.addworkers.desc"}}</p>
|
||||
<form method="POST" action="{{.Link}}/add">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="ui form">
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label>{{.locale.Tr "admin.monitor.queue.numberworkers"}}</label>
|
||||
<input name="number" type="text" placeholder="{{.locale.Tr "admin.monitor.queue.pool.addworkers.numberworkers.placeholder"}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{.locale.Tr "admin.monitor.queue.pool.timeout"}}</label>
|
||||
<input name="timeout" type="text" placeholder="{{.locale.Tr "admin.monitor.queue.pool.addworkers.timeout.placeholder"}}">
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui submit button">{{.locale.Tr "admin.monitor.queue.pool.addworkers.submit"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{if .Queue.Pausable}}
|
||||
{{if .Queue.IsPaused}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue.pool.resume.title"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p>{{.locale.Tr "admin.monitor.queue.pool.resume.desc"}}</p>
|
||||
<form method="POST" action="{{.Link}}/resume">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="ui form">
|
||||
<button class="ui submit button">{{.locale.Tr "admin.monitor.queue.pool.resume.submit"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{else}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue.pool.pause.title"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p>{{.locale.Tr "admin.monitor.queue.pool.pause.desc"}}</p>
|
||||
<form method="POST" action="{{.Link}}/pause">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="ui form">
|
||||
<button class="ui submit button">{{.locale.Tr "admin.monitor.queue.pool.pause.submit"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queues"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<table class="ui very basic striped table unstackable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.name"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.type"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.exemplar"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.numberworkers"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.numberinqueue"}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $qid, $q := .Queues}}
|
||||
<tr>
|
||||
<td>{{$q.GetName}}</td>
|
||||
<td>{{$q.GetType}}</td>
|
||||
<td>{{$q.GetItemTypeName}}</td>
|
||||
<td>{{$sum := $q.GetWorkerNumber}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
||||
<td>{{$sum = $q.GetQueueItemNumber}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
||||
<td><a href="{{$.Link}}/queue/{{$qid}}" class="button">{{if lt $sum 0}}{{$.locale.Tr "admin.monitor.queue.review"}}{{else}}{{$.locale.Tr "admin.monitor.queue.review_add"}}{{end}}</a>
|
||||
</tr>
|
||||
{{end}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue.pool.flush.title"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p>{{.locale.Tr "admin.monitor.queue.pool.flush.desc"}}</p>
|
||||
<form method="POST" action="{{.Link}}/flush">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="ui form">
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label>{{.locale.Tr "admin.monitor.queue.pool.timeout"}}</label>
|
||||
<input name="timeout" type="text" placeholder="{{.locale.Tr "admin.monitor.queue.pool.addworkers.timeout.placeholder"}}">
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui submit button">{{.locale.Tr "admin.monitor.queue.pool.flush.submit"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue.pool.workers.title"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<table class="ui very basic striped table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.numberworkers"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.start"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.pool.timeout"}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Queue.Workers}}
|
||||
<tr>
|
||||
<td>{{.Workers}}{{if .IsFlusher}}<span title="{{$.locale.Tr "admin.monitor.queue.flush"}}">{{svg "octicon-sync"}}</span>{{end}}</td>
|
||||
<td>{{DateTime "full" .Start}}</td>
|
||||
<td>{{if .HasTimeout}}{{DateTime "full" .Timeout}}{{else}}-{{end}}</td>
|
||||
<td>
|
||||
<a class="delete-button" href="" data-url="{{$.Link}}/cancel/{{.PID}}" data-id="{{.PID}}" data-name="{{.Workers}}" title="{{$.locale.Tr "remove"}}">{{svg "octicon-trash"}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr>
|
||||
<td colspan="4">{{.locale.Tr "admin.monitor.queue.pool.workers.none"}}
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue.configuration"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<pre>{{JsonUtils.PrettyIndent .Queue.Configuration}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui g-modal-confirm delete modal">
|
||||
<div class="header">
|
||||
{{.locale.Tr "admin.monitor.queue.pool.cancel"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{$.locale.Tr "admin.monitor.queue.pool.cancel_notices" `<span class="name"></span>` | Safe}}</p>
|
||||
<p>{{$.locale.Tr "admin.monitor.queue.pool.cancel_desc"}}</p>
|
||||
</div>
|
||||
{{template "base/modal_actions_confirm" .}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{template "admin/layout_footer" .}}
|
||||
|
48
templates/admin/queue_manage.tmpl
Normal file
48
templates/admin/queue_manage.tmpl
Normal file
@@ -0,0 +1,48 @@
|
||||
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin monitor")}}
|
||||
<div class="admin-setting-content">
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue" .Queue.GetName}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<table class="ui very basic striped table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.name"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.type"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.exemplar"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.numberworkers"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.maxnumberworkers"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.queue.numberinqueue"}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{.Queue.GetName}}</td>
|
||||
<td>{{.Queue.GetType}}</td>
|
||||
<td>{{.Queue.GetItemTypeName}}</td>
|
||||
<td>{{$sum := .Queue.GetWorkerNumber}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
||||
<td>{{if lt $sum 0}}-{{else}}{{.Queue.GetWorkerMaxNumber}}{{end}}</td>
|
||||
<td>{{$sum = .Queue.GetQueueItemNumber}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "admin.monitor.queue.settings.title"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p>{{.locale.Tr "admin.monitor.queue.settings.desc"}}</p>
|
||||
<form method="POST" action="{{.Link}}/set">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="ui form">
|
||||
<div class="inline field">
|
||||
<label for="max-number">{{.locale.Tr "admin.monitor.queue.settings.maxnumberworkers"}}</label>
|
||||
<input name="max-number" type="text" placeholder="{{.locale.Tr "admin.monitor.queue.settings.maxnumberworkers.placeholder" .Queue.GetWorkerMaxNumber}}">
|
||||
</div>
|
||||
<button class="ui submit button">{{.locale.Tr "admin.monitor.queue.settings.submit"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{template "admin/layout_footer" .}}
|
Reference in New Issue
Block a user