Dark magic to allow serializing session to database on shutdown
This commit is contained in:
parent
5560b140f5
commit
1cd41cc159
@ -255,7 +255,7 @@ class API extends InternalDoc
|
||||
$this->API->destructing = true;
|
||||
$this->API->unreference();
|
||||
}
|
||||
if (isset($this->wrapper)) {
|
||||
if (isset($this->wrapper) && !Magic::$signaled) {
|
||||
$this->logger->logger('Prompting final serialization...');
|
||||
Tools::wait($this->wrapper->serialize());
|
||||
$this->logger->logger('Done final serialization!');
|
||||
|
@ -204,6 +204,20 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
'msg_resend_ans_req',
|
||||
];
|
||||
const DEFAULT_GETUPDATES_PARAMS = ['offset' => 0, 'limit' => null, 'timeout' => 100];
|
||||
/**
|
||||
* Array of references to all instances of MTProto.
|
||||
*
|
||||
* This seems like a recipe for memory leaks, but this is actually required to allow saving the session on shutdown.
|
||||
* When using a network I/O-based database+the EvDriver of AMPHP, calling die(); causes premature garbage collection of the event loop.
|
||||
* This garbage collection happens always, even if a reference to the event handler is already present elsewhere (probably ev dark magic).
|
||||
*
|
||||
* Finally, this causes the process to hang on shutdown, since the database driver cannot receive a reply from the server, because the event loop is down.
|
||||
*
|
||||
* To avoid this, we store each MTProto instance in here (unreferencing on shutdown in unreference()), and call serialize() on all instances before calling die; in Magic.
|
||||
*
|
||||
* @var self[]
|
||||
*/
|
||||
public static array $references = [];
|
||||
/**
|
||||
* Instance of wrapper API.
|
||||
*
|
||||
@ -505,9 +519,23 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
return $data;
|
||||
}
|
||||
yield $this->session->offsetSet('data', $data);
|
||||
var_dump("Saved!");
|
||||
return $this->session;
|
||||
}
|
||||
/**
|
||||
* Serialize all instances.
|
||||
*
|
||||
* CALLED ONLY ON SHUTDOWN.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function serializeAll(): void
|
||||
{
|
||||
Logger::log('Prompting final serialization (SHUTDOWN)...');
|
||||
foreach (self::$references as $instance) {
|
||||
Tools::wait($instance->wrapper->serialize());
|
||||
}
|
||||
Logger::log('Done final serialization (SHUTDOWN)!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor function.
|
||||
@ -519,6 +547,7 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
*/
|
||||
public function __magic_construct(SettingsAbstract $settings, APIWrapper $wrapper)
|
||||
{
|
||||
self::$references[\spl_object_hash($this)] = $this;
|
||||
$this->wrapper = $wrapper;
|
||||
$this->setInitPromise($this->__construct_async($settings));
|
||||
}
|
||||
@ -1023,6 +1052,8 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
*/
|
||||
public function wakeup(SettingsAbstract $settings, APIWrapper $wrapper): \Generator
|
||||
{
|
||||
// Set reference to itself
|
||||
self::$references[\spl_object_hash($this)] = $this;
|
||||
// Set API wrapper
|
||||
$this->wrapper = $wrapper;
|
||||
// BC stuff
|
||||
@ -1132,6 +1163,9 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
public function unreference(): void
|
||||
{
|
||||
$this->logger->logger("Will unreference instance");
|
||||
if (isset(self::$references[\spl_object_hash($this)])) {
|
||||
unset(self::$references[\spl_object_hash($this)]);
|
||||
}
|
||||
$this->stopLoops();
|
||||
if (isset($this->seqUpdater)) {
|
||||
$this->seqUpdater->signal(true);
|
||||
@ -1153,7 +1187,6 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
$datacenter->disconnect();
|
||||
}
|
||||
$this->logger->logger("Unreferenced instance");
|
||||
|
||||
}
|
||||
/**
|
||||
* Destructor.
|
||||
|
@ -59,7 +59,7 @@ class Magic
|
||||
*/
|
||||
public static $isFork = false;
|
||||
/**
|
||||
* Whether this is an IPC worker
|
||||
* Whether this is an IPC worker.
|
||||
*/
|
||||
public static bool $isIpcWorker = false;
|
||||
/**
|
||||
@ -234,7 +234,7 @@ class Magic
|
||||
// Setup error reporting
|
||||
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||
\set_exception_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionHandler']);
|
||||
self::$isIpcWorker = defined(\MADELINE_WORKER_TYPE::class) ? \MADELINE_WORKER_TYPE === 'madeline-ipc' : false;
|
||||
self::$isIpcWorker = \defined(\MADELINE_WORKER_TYPE::class) ? \MADELINE_WORKER_TYPE === 'madeline-ipc' : false;
|
||||
if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') {
|
||||
try {
|
||||
\error_reporting(E_ALL);
|
||||
@ -412,6 +412,7 @@ class Magic
|
||||
$driver->unreference($key);
|
||||
}
|
||||
}
|
||||
MTProto::serializeAll();
|
||||
Loop::stop();
|
||||
die($code);
|
||||
}
|
||||
|
@ -425,6 +425,18 @@ class Connection extends SettingsAbstract
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set proxies.
|
||||
*
|
||||
* @param array $proxies Proxies
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setProxy(array $proxies): self
|
||||
{
|
||||
$this->proxy = $proxies;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Clear proxies.
|
||||
*
|
||||
|
@ -46,7 +46,7 @@ abstract class SettingsAbstract
|
||||
!isset($defaults[$name])
|
||||
|| $other->{$name} !== $defaults[$name] // Isn't equal to the default value
|
||||
)
|
||||
&& $other->{$name} !== $this->{"get$uc"}
|
||||
&& $other->{$name} !== $this->{$name}
|
||||
) {
|
||||
$this->{"set$uc"}($other->{$name});
|
||||
$this->changed = true;
|
||||
|
@ -52,6 +52,7 @@ class Shutdown
|
||||
foreach (self::$callbacks as $callback) {
|
||||
$callback();
|
||||
}
|
||||
Magic::shutdown(0);
|
||||
}
|
||||
/**
|
||||
* Add a callback for script shutdown.
|
||||
|
Loading…
Reference in New Issue
Block a user