| 
									
										
										
										
											2023-03-12 16:00:57 +01:00
										 |  |  | // GoToSocial | 
					
						
							|  |  |  | // Copyright (C) GoToSocial Authors admin@gotosocial.org | 
					
						
							|  |  |  | // SPDX-License-Identifier: AGPL-3.0-or-later | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | // GNU Affero General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | package workers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	"log" | 
					
						
							|  |  |  | 	"runtime" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"codeberg.org/gruf/go-runners" | 
					
						
							| 
									
										
										
										
											2024-04-11 10:45:35 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/config" | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/messages" | 
					
						
							| 
									
										
										
										
											2023-11-04 20:21:20 +00:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/scheduler" | 
					
						
							| 
									
										
										
										
											2024-04-11 10:45:35 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/transport/delivery" | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Workers struct { | 
					
						
							|  |  |  | 	// Main task scheduler instance. | 
					
						
							| 
									
										
										
										
											2023-11-04 20:21:20 +00:00
										 |  |  | 	Scheduler scheduler.Scheduler | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 10:45:35 +01:00
										 |  |  | 	// Delivery provides a worker pool that | 
					
						
							|  |  |  | 	// handles outgoing ActivityPub deliveries. | 
					
						
							|  |  |  | 	// It contains an embedded (but accessible) | 
					
						
							|  |  |  | 	// indexed queue of Delivery{} objects. | 
					
						
							|  |  |  | 	Delivery delivery.WorkerPool | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-28 16:45:21 +01:00
										 |  |  | 	// ClientAPI provides a worker pool that handles both | 
					
						
							|  |  |  | 	// incoming client actions, and our own side-effects. | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 	ClientAPI runners.WorkerPool | 
					
						
							| 
									
										
										
										
											2023-04-28 16:45:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Federator provides a worker pool that handles both | 
					
						
							|  |  |  | 	// incoming federated actions, and our own side-effects. | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 	Federator runners.WorkerPool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Enqueue functions for clientAPI / federator worker pools, | 
					
						
							|  |  |  | 	// these are pointers to Processor{}.Enqueue___() msg functions. | 
					
						
							|  |  |  | 	// This prevents dependency cycling as Processor depends on Workers. | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	EnqueueClientAPI func(context.Context, ...messages.FromClientAPI) | 
					
						
							| 
									
										
										
										
											2023-08-09 19:14:33 +02:00
										 |  |  | 	EnqueueFediAPI   func(context.Context, ...messages.FromFediAPI) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-04 15:55:17 +02:00
										 |  |  | 	// Blocking processing functions for clientAPI / federator. | 
					
						
							|  |  |  | 	// These are pointers to Processor{}.Process___() msg functions. | 
					
						
							|  |  |  | 	// This prevents dependency cycling as Processor depends on Workers. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// Rather than queueing messages for asynchronous processing, these | 
					
						
							|  |  |  | 	// functions will process immediately and in a blocking manner, and | 
					
						
							|  |  |  | 	// will not use up a worker slot. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// As such, you should only call them in special cases where something | 
					
						
							|  |  |  | 	// synchronous needs to happen before you can do something else. | 
					
						
							|  |  |  | 	ProcessFromClientAPI func(context.Context, messages.FromClientAPI) error | 
					
						
							|  |  |  | 	ProcessFromFediAPI   func(context.Context, messages.FromFediAPI) error | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	// Media manager worker pools. | 
					
						
							|  |  |  | 	Media runners.WorkerPool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// prevent pass-by-value. | 
					
						
							|  |  |  | 	_ nocopy | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 10:45:35 +01:00
										 |  |  | // Start will start all of the contained | 
					
						
							|  |  |  | // worker pools (and global scheduler). | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | func (w *Workers) Start() { | 
					
						
							|  |  |  | 	// Get currently set GOMAXPROCS. | 
					
						
							|  |  |  | 	maxprocs := runtime.GOMAXPROCS(0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-04 20:21:20 +00:00
										 |  |  | 	tryUntil("starting scheduler", 5, w.Scheduler.Start) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 10:45:35 +01:00
										 |  |  | 	tryUntil("start delivery workerpool", 5, func() bool { | 
					
						
							|  |  |  | 		n := config.GetAdvancedSenderMultiplier() | 
					
						
							|  |  |  | 		if n < 1 { | 
					
						
							|  |  |  | 			// clamp min senders to 1. | 
					
						
							|  |  |  | 			return w.Delivery.Start(1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return w.Delivery.Start(n * maxprocs) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 	tryUntil("starting client API workerpool", 5, func() bool { | 
					
						
							|  |  |  | 		return w.ClientAPI.Start(4*maxprocs, 400*maxprocs) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 	tryUntil("starting federator workerpool", 5, func() bool { | 
					
						
							|  |  |  | 		return w.Federator.Start(4*maxprocs, 400*maxprocs) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tryUntil("starting media workerpool", 5, func() bool { | 
					
						
							|  |  |  | 		return w.Media.Start(8*maxprocs, 80*maxprocs) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Stop will stop all of the contained worker pools (and global scheduler). | 
					
						
							|  |  |  | func (w *Workers) Stop() { | 
					
						
							|  |  |  | 	tryUntil("stopping scheduler", 5, w.Scheduler.Stop) | 
					
						
							| 
									
										
										
										
											2024-04-11 10:45:35 +01:00
										 |  |  | 	tryUntil("stopping delivery workerpool", 5, w.Delivery.Stop) | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 	tryUntil("stopping client API workerpool", 5, w.ClientAPI.Stop) | 
					
						
							|  |  |  | 	tryUntil("stopping federator workerpool", 5, w.Federator.Stop) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	tryUntil("stopping media workerpool", 5, w.Media.Stop) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // nocopy when embedded will signal linter to | 
					
						
							|  |  |  | // error on pass-by-value of parent struct. | 
					
						
							|  |  |  | type nocopy struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (*nocopy) Lock() {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (*nocopy) Unlock() {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // tryUntil will attempt to call 'do' for 'count' attempts, before panicking with 'msg'. | 
					
						
							|  |  |  | func tryUntil(msg string, count int, do func() bool) { | 
					
						
							|  |  |  | 	for i := 0; i < count; i++ { | 
					
						
							|  |  |  | 		if do() { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	log.Panicf("failed %s after %d tries", msg, count) | 
					
						
							|  |  |  | } |