kopia lustrzana https://github.com/jointakahe/takahe
				
				
				
			
		
			
				
	
	
		
			64 wiersze
		
	
	
		
			2.7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
			
		
		
	
	
			64 wiersze
		
	
	
		
			2.7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
| Stator
 | |
| ======
 | |
| 
 | |
| Takahē's background task system is called Stator, and rather than being a
 | |
| transitional task queue, it is instead a *reconciliation loop* system; the
 | |
| workers look for objects that could have actions taken, try to take them, and
 | |
| update them if successful.
 | |
| 
 | |
| As someone running Takahē, the most important aspects of this are:
 | |
| 
 | |
| * You have to run at least one Stator worker to make things like follows,
 | |
|   posting, and timelines work.
 | |
| 
 | |
| * You can run as many workers as you want; there is a locking system to ensure
 | |
|   they can coexist.
 | |
| 
 | |
| * You can get away without running any workers for a few minutes; the server
 | |
|   will continue to accept posts and follows from other servers, and will
 | |
|   process them when a worker comes back up.
 | |
| 
 | |
| * There is no separate queue to run, flush or replay; it is all stored in the
 | |
|   main database.
 | |
| 
 | |
| * If all your workers die, just restart them, and within a few minutes the
 | |
|   existing locks will time out and the system will recover itself and process
 | |
|   everything that's pending.
 | |
| 
 | |
| You run a worker via the command ``manage.py runstator``. It will run forever
 | |
| until it is killed; send SIGINT (Ctrl-C) to it once to have it enter graceful
 | |
| shutdown, and a second time to force exiting immediately.
 | |
| 
 | |
| 
 | |
| Technical Details
 | |
| -----------------
 | |
| 
 | |
| Each object managed by Stator has a set of extra columns:
 | |
| 
 | |
| * ``state``, the name of a state in a state machine
 | |
| * ``state_ready``, a boolean saying if it's ready to have a transition tried
 | |
| * ``state_changed``, when it entered into its current state
 | |
| * ``state_attempted``, when a transition was last attempted
 | |
| * ``state_locked_until``, when the entry is locked by a worker until
 | |
| 
 | |
| They also have an associated state machine which is a subclass of
 | |
| ``stator.graph.StateGraph``, which will define a series of states, the
 | |
| possible transitions between them, and handlers that run for each state to see
 | |
| if a transition is possible.
 | |
| 
 | |
| An object becoming ready for execution happens first:
 | |
| 
 | |
| * If it's just entered into a new state, or just created, it is marked ready.
 | |
| * If ``state_attempted`` is far enough in the past (based on the ``try_interval``
 | |
|   of the current state), a small scheduling loop marks it as ready.
 | |
| 
 | |
| Then, in the main fast loop of the worker, it:
 | |
| 
 | |
| * Selects an item with ``state_ready`` that is in a state it can handle (some
 | |
|   states are "externally progressed" and will not have handlers run)
 | |
| * Fires up a coroutine for that handler and lets it run
 | |
| * When that coroutine exits, sees if it returned a new state name and if so,
 | |
|   transitions the object to that state.
 | |
| * If that coroutine errors or exits with ``None`` as a return value, it marks
 | |
|   down the attempt and leaves the object to be rescheduled after its ``try_interval``.
 |