Feat: group requests in bulks.

This commit is contained in:
Alexander Pankratov 2023-09-02 23:45:01 +02:00
parent 0a0305dc27
commit c554bda966
6 changed files with 139 additions and 77 deletions

View File

@ -8,6 +8,12 @@ SERVER_PORT=9503
MEMORY_LIMIT=256M
TIMEZONE=UTC
# REQUEST WILL BE GROUPED INTO BULKS AND EXECUTED AS SINGLE BULK
# VALUE IN SECOND
# DECREASE TO REDUCE LATENCY, INCREASE TO REDUCE LOAD ON SERVER.
# SET to 0 to DISABLE
REQUESTS_BULK_INTERVAL=0.5
# List of allowed clients. Separate with comma.
# Leave blanc, to allow requests from all IP (THIS WILL MAKE API UNSECURE!)
# To recieve requests from internet also need to (THIS WILL MAKE API UNSECURE!):

View File

@ -10,6 +10,12 @@ SERVER_PORT=9503
MEMORY_LIMIT=256M
TIMEZONE=UTC
# REQUEST WILL BE GROUPED INTO BULKS AND EXECUTED AS SINGLE BULK
# VALUE IN SECOND
# DECREASE TO REDUCE LATENCY, INCREASE TO REDUCE LOAD ON SERVER.
# SET to 0 to DISABLE
REQUESTS_BULK_INTERVAL=0.5
# List of allowed clients. Separate with comma.
# Leave blanc, to allow requests from all IP (THIS WILL MAKE API UNSECURE!)
IP_WHITELIST=127.0.0.1

146
composer.lock generated
View File

@ -89,16 +89,16 @@
},
{
"name": "amphp/byte-stream",
"version": "v2.0.1",
"version": "v2.0.2",
"source": {
"type": "git",
"url": "https://github.com/amphp/byte-stream.git",
"reference": "7e7a77579f3e90c6fbd56e49628e6ace02d8f88a"
"reference": "408a3b4fc4f4c7604575dc8704f18c1bd91c3ceb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/byte-stream/zipball/7e7a77579f3e90c6fbd56e49628e6ace02d8f88a",
"reference": "7e7a77579f3e90c6fbd56e49628e6ace02d8f88a",
"url": "https://api.github.com/repos/amphp/byte-stream/zipball/408a3b4fc4f4c7604575dc8704f18c1bd91c3ceb",
"reference": "408a3b4fc4f4c7604575dc8704f18c1bd91c3ceb",
"shasum": ""
},
"require": {
@ -119,7 +119,8 @@
"type": "library",
"autoload": {
"files": [
"src/functions.php"
"src/functions.php",
"src/Internal/functions.php"
],
"psr-4": {
"Amp\\ByteStream\\": "src"
@ -151,7 +152,7 @@
],
"support": {
"issues": "https://github.com/amphp/byte-stream/issues",
"source": "https://github.com/amphp/byte-stream/tree/v2.0.1"
"source": "https://github.com/amphp/byte-stream/tree/v2.0.2"
},
"funding": [
{
@ -159,7 +160,7 @@
"type": "github"
}
],
"time": "2023-02-03T04:06:20+00:00"
"time": "2023-09-01T04:41:26+00:00"
},
{
"name": "amphp/cache",
@ -474,28 +475,28 @@
},
{
"name": "amphp/http",
"version": "v2.0.0",
"version": "v2.1.0",
"source": {
"type": "git",
"url": "https://github.com/amphp/http.git",
"reference": "f8bb94a2b079aa8e30ad78b5374df787a2122dfe"
"reference": "9f3500bef4bb15cf41987f21136539c0a06555a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/http/zipball/f8bb94a2b079aa8e30ad78b5374df787a2122dfe",
"reference": "f8bb94a2b079aa8e30ad78b5374df787a2122dfe",
"url": "https://api.github.com/repos/amphp/http/zipball/9f3500bef4bb15cf41987f21136539c0a06555a3",
"reference": "9f3500bef4bb15cf41987f21136539c0a06555a3",
"shasum": ""
},
"require": {
"amphp/hpack": "^3",
"amphp/parser": "^1.1",
"league/uri-components": "^2.4",
"league/uri-components": "^2.4.2 | ^7.1",
"php": ">=8.1",
"psr/http-message": "^1 || ^2"
"psr/http-message": "^1 | ^2"
},
"require-dev": {
"amphp/php-cs-fixer-config": "^2",
"league/uri": "^6.8",
"league/uri": "^6.8 | ^7.1",
"phpunit/phpunit": "^9",
"psalm/phar": "^5.4"
},
@ -526,7 +527,7 @@
"description": "Basic HTTP primitives which can be shared by servers and clients.",
"support": {
"issues": "https://github.com/amphp/http/issues",
"source": "https://github.com/amphp/http/tree/v2.0.0"
"source": "https://github.com/amphp/http/tree/v2.1.0"
},
"funding": [
{
@ -534,20 +535,20 @@
"type": "github"
}
],
"time": "2023-04-12T19:20:53+00:00"
"time": "2023-08-22T19:50:46+00:00"
},
{
"name": "amphp/http-client",
"version": "v5.0.0-beta.13",
"version": "v5.0.0-beta.14",
"source": {
"type": "git",
"url": "https://github.com/amphp/http-client.git",
"reference": "fd5b005d9799aab0e67764cf889586660516cd14"
"reference": "a9f2bebe03baaac7fa029b5d01bb66ab4a9c5b5b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/http-client/zipball/fd5b005d9799aab0e67764cf889586660516cd14",
"reference": "fd5b005d9799aab0e67764cf889586660516cd14",
"url": "https://api.github.com/repos/amphp/http-client/zipball/a9f2bebe03baaac7fa029b5d01bb66ab4a9c5b5b",
"reference": "a9f2bebe03baaac7fa029b5d01bb66ab4a9c5b5b",
"shasum": ""
},
"require": {
@ -588,6 +589,7 @@
},
"autoload": {
"files": [
"src/functions.php",
"src/Internal/functions.php"
],
"psr-4": {
@ -624,7 +626,7 @@
],
"support": {
"issues": "https://github.com/amphp/http-client/issues",
"source": "https://github.com/amphp/http-client/tree/v5.0.0-beta.13"
"source": "https://github.com/amphp/http-client/tree/v5.0.0-beta.14"
},
"funding": [
{
@ -632,7 +634,7 @@
"type": "github"
}
],
"time": "2023-08-15T20:25:04+00:00"
"time": "2023-08-23T20:15:15+00:00"
},
{
"name": "amphp/http-client-cookies",
@ -717,12 +719,12 @@
"source": {
"type": "git",
"url": "https://github.com/amphp/http-server.git",
"reference": "4e6e8b1e23c55ff8b1377f6eaccda3f49894723e"
"reference": "5057e59b7119314f2f1f5c7740daf3bcbbd1f163"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/http-server/zipball/4e6e8b1e23c55ff8b1377f6eaccda3f49894723e",
"reference": "4e6e8b1e23c55ff8b1377f6eaccda3f49894723e",
"url": "https://api.github.com/repos/amphp/http-server/zipball/5057e59b7119314f2f1f5c7740daf3bcbbd1f163",
"reference": "5057e59b7119314f2f1f5c7740daf3bcbbd1f163",
"shasum": ""
},
"require": {
@ -734,11 +736,11 @@
"amphp/pipeline": "^1",
"amphp/socket": "^2.1",
"amphp/sync": "^2",
"league/uri": "^6",
"league/uri-interfaces": "^2.3",
"league/uri": "^6.8 | ^7.1",
"league/uri-interfaces": "^2.3 | ^7.1",
"php": ">=8.1",
"psr/http-message": "^1",
"psr/log": "^1|^2|^3",
"psr/http-message": "^1 | ^2",
"psr/log": "^1 | ^2 | ^3",
"revolt/event-loop": "^1"
},
"require-dev": {
@ -746,7 +748,7 @@
"amphp/log": "^2",
"amphp/php-cs-fixer-config": "^2",
"amphp/phpunit-util": "^3",
"league/uri-components": "^2",
"league/uri-components": "^2.4.2 | ^7.1",
"monolog/monolog": "^3",
"phpunit/phpunit": "^9",
"psalm/phar": "^5.4"
@ -807,27 +809,27 @@
"type": "github"
}
],
"time": "2023-08-20T19:03:40+00:00"
"time": "2023-09-01T05:04:07+00:00"
},
{
"name": "amphp/http-server-form-parser",
"version": "v2.0.0-beta.3",
"version": "v2.0.0",
"source": {
"type": "git",
"url": "https://github.com/amphp/http-server-form-parser.git",
"reference": "42193795723ea72e950b74f0a9075bb794c542f0"
"reference": "6f160914a1cd9aaa104b589c0c590613600bfa70"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/http-server-form-parser/zipball/42193795723ea72e950b74f0a9075bb794c542f0",
"reference": "42193795723ea72e950b74f0a9075bb794c542f0",
"url": "https://api.github.com/repos/amphp/http-server-form-parser/zipball/6f160914a1cd9aaa104b589c0c590613600bfa70",
"reference": "6f160914a1cd9aaa104b589c0c590613600bfa70",
"shasum": ""
},
"require": {
"amphp/amp": "^3",
"amphp/byte-stream": "^2",
"amphp/http": "^2",
"amphp/http-server": "^3",
"amphp/http-server": "^3.2",
"amphp/pipeline": "^1",
"php": ">=8.1",
"revolt/event-loop": "^1"
@ -869,19 +871,20 @@
"email": "aaron@trowski.com"
}
],
"description": "A form parser for Amp's HTTP parser.",
"homepage": "https://github.com/amphp/http-server-form-parser",
"description": "An HTTP server plugin that simplifies form data handling. Effortlessly parse incoming form submissions and extracting its data.",
"homepage": "https://amphp.org/http-server-form-parser",
"keywords": [
"amp",
"amphp",
"async",
"form",
"http",
"non-blocking"
"non-blocking",
"revolt"
],
"support": {
"issues": "https://github.com/amphp/http-server-form-parser/issues",
"source": "https://github.com/amphp/http-server-form-parser/tree/v2.0.0-beta.3"
"source": "https://github.com/amphp/http-server-form-parser/tree/v2.0.0"
},
"funding": [
{
@ -889,7 +892,7 @@
"type": "github"
}
],
"time": "2023-04-22T15:36:02+00:00"
"time": "2023-08-25T02:52:20+00:00"
},
{
"name": "amphp/http-server-router",
@ -1116,16 +1119,16 @@
},
{
"name": "amphp/parallel",
"version": "v2.2.1",
"version": "v2.2.2",
"source": {
"type": "git",
"url": "https://github.com/amphp/parallel.git",
"reference": "ba11031b8664134b13c150530ae041a75e631858"
"reference": "f54bb4090670397544f74e14a1e650bf2cfd853b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/parallel/zipball/ba11031b8664134b13c150530ae041a75e631858",
"reference": "ba11031b8664134b13c150530ae041a75e631858",
"url": "https://api.github.com/repos/amphp/parallel/zipball/f54bb4090670397544f74e14a1e650bf2cfd853b",
"reference": "f54bb4090670397544f74e14a1e650bf2cfd853b",
"shasum": ""
},
"require": {
@ -1187,7 +1190,7 @@
],
"support": {
"issues": "https://github.com/amphp/parallel/issues",
"source": "https://github.com/amphp/parallel/tree/v2.2.1"
"source": "https://github.com/amphp/parallel/tree/v2.2.2"
},
"funding": [
{
@ -1195,7 +1198,7 @@
"type": "github"
}
],
"time": "2023-05-22T03:33:27+00:00"
"time": "2023-08-30T17:43:42+00:00"
},
{
"name": "amphp/parser",
@ -2515,12 +2518,12 @@
"source": {
"type": "git",
"url": "https://github.com/danog/MadelineProto.git",
"reference": "dc34a380b3dd936c0dfc753dc89aa7389d5ac377"
"reference": "546e9a0d23ad4f05a5e2b3446be7315d4e53b95b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/danog/MadelineProto/zipball/dc34a380b3dd936c0dfc753dc89aa7389d5ac377",
"reference": "dc34a380b3dd936c0dfc753dc89aa7389d5ac377",
"url": "https://api.github.com/repos/danog/MadelineProto/zipball/546e9a0d23ad4f05a5e2b3446be7315d4e53b95b",
"reference": "546e9a0d23ad4f05a5e2b3446be7315d4e53b95b",
"shasum": ""
},
"require": {
@ -2572,7 +2575,6 @@
"danog/phpdoc": "^0.1.7",
"dg/bypass-finals": "dev-master",
"ext-ctype": "*",
"leproxy/leproxy": "^0.2.2",
"phpdocumentor/reflection-docblock": "dev-master",
"phpdocumentor/type-resolver": "1.x-dev@dev",
"phpunit/phpunit": "^9",
@ -2637,7 +2639,7 @@
"type": "github"
}
],
"time": "2023-08-21T13:09:02+00:00"
"time": "2023-09-02T20:24:26+00:00"
},
{
"name": "danog/primemodule",
@ -2755,16 +2757,16 @@
},
{
"name": "dasprid/enum",
"version": "1.0.4",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/DASPRiD/Enum.git",
"reference": "8e6b6ea76eabbf19ea2bf5b67b98e1860474012f"
"reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8e6b6ea76eabbf19ea2bf5b67b98e1860474012f",
"reference": "8e6b6ea76eabbf19ea2bf5b67b98e1860474012f",
"url": "https://api.github.com/repos/DASPRiD/Enum/zipball/6faf451159fb8ba4126b925ed2d78acfce0dc016",
"reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016",
"shasum": ""
},
"require": {
@ -2799,9 +2801,9 @@
],
"support": {
"issues": "https://github.com/DASPRiD/Enum/issues",
"source": "https://github.com/DASPRiD/Enum/tree/1.0.4"
"source": "https://github.com/DASPRiD/Enum/tree/1.0.5"
},
"time": "2023-03-01T18:44:03+00:00"
"time": "2023-08-25T16:18:39+00:00"
},
{
"name": "daverandom/libdns",
@ -3906,16 +3908,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
@ -3930,7 +3932,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -3968,7 +3970,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
@ -3984,20 +3986,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
@ -4012,7 +4014,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -4051,7 +4053,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
@ -4067,7 +4069,7 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-07-28T09:04:16+00:00"
},
{
"name": "vlucas/phpdotenv",

View File

@ -15,7 +15,7 @@ $settings = [
],
'logger' => [ // Logger settings
'type' => Logger::CALLABLE_LOGGER, // 0 - Logs disabled, 3 - echo logs.
'extra' => LogObserver::class . '::log',
'extra' => LogObserver::log(...),
'level' => (int)getenv('LOGGER_LEVEL'), // Logging level, available logging levels are: ULTRA_VERBOSE - 5, VERBOSE - 4 , NOTICE - 3, WARNING - 2, ERROR - 1, FATAL_ERROR - 0.
],
'rpc' => [
@ -53,6 +53,7 @@ $settings = [
explode(',', (string)getenv('IP_WHITELIST'))
)
),
'bulk_interval' => (float)getenv('REQUESTS_BULK_INTERVAL')
],
'health_check' => [
'enabled' => (bool)filter_var((string)getenv('HEALTHCHECK_ENABLED'), FILTER_VALIDATE_BOOL),

View File

@ -4,7 +4,7 @@ namespace TelegramApiServer\Controllers;
use Amp\Future;
use Amp\Http\Server\FormParser\StreamedField;
use Amp\Http\Server\FormParser\StreamingParser;
use Amp\Http\Server\FormParser\StreamingFormParser;
use Amp\Http\Server\Request;
use Amp\Http\Server\RequestHandler\ClosureRequestHandler;
use Amp\Http\Server\Response;
@ -18,6 +18,7 @@ use TelegramApiServer\MadelineProtoExtensions\ApiExtensions;
use TelegramApiServer\MadelineProtoExtensions\SystemApiExtensions;
use Throwable;
use UnexpectedValueException;
use function Amp\delay;
use function mb_strpos;
abstract class AbstractApiController
@ -95,7 +96,7 @@ abstract class AbstractApiController
switch (true) {
case $contentType === 'application/x-www-form-urlencoded':
case mb_strpos($contentType, 'multipart/form-data') !== false:
$form = (new StreamingParser())->parseForm($this->request);
$form = (new StreamingFormParser())->parseForm($this->request);
$post = [];
while ($form->continue()) {

View File

@ -2,8 +2,18 @@
namespace TelegramApiServer\Controllers;
use Amp\Sync\LocalKeyedMutex;
use Amp\Sync\LocalMutex;
use Amp\Sync\StaticKeyMutex;
use Amp\Sync\SyncException;
use Exception;
use Revolt\EventLoop;
use TelegramApiServer\Client;
use TelegramApiServer\Config;
use TelegramApiServer\Logger;
use function Amp\async;
use function Amp\delay;
use function Amp\Future\awaitAll;
class ApiController extends AbstractApiController
{
@ -25,10 +35,46 @@ class ApiController extends AbstractApiController
/**
* @throws Exception
*/
protected function callApi()
protected function callApi(): mixed
{
$madelineProto = Client::getInstance()->getSession($this->session);
return $this->callApiCommon($madelineProto);
$tick = Config::getInstance()->get('api.bulk_interval');
if (!$tick) {
return $this->callApiCommon($madelineProto);
}
//GROUP REQUESTS IN BULKS
static $futures = [];
$futures[] = $future = async($this->callApiCommon(...), $madelineProto);
delay($this->waitNextTick());
if ($futures) {
awaitAll($futures);
Logger::getInstance()->notice("Executed bulk requests:" . count($futures));
$futures = [];
}
return $future->await();
}
/**
* Sync threads execution via time ticks
* Need to enable madelineProto futures bulk execution
* @param float $tick interval of execution in seconds.
*/
protected function waitNextTick(float $tick = 0.5): float {
$tickMs = $tick * 1000;
$now = (int)(microtime(true) * 1000);
$currentTick = intdiv((int)(microtime(true) * 1000), $tickMs);
$nextTick = ($currentTick + 1);
$nextTickTime = $nextTick * $tickMs;
$wait = round(($nextTickTime - $now)/1000, 3);
Logger::getInstance()->notice("Waiting $wait seconds before tick");
return $wait;
}
}