Update MTPROXY_CHECK_TIMEOUT to 45s in docker-compose and documentation; adjust default timeout handling in code for improved performance under slow network conditions.
Publish mtproxy_checker Docker image / test (push) Successful in 13s
Publish mtproxy_checker Docker image / build-and-push (push) Successful in 52s

This commit is contained in:
Denozordec
2026-04-11 13:39:52 +07:00
parent 6a6183a994
commit 6f2dbcbca3
5 changed files with 25 additions and 6 deletions
+2 -1
View File
@@ -58,7 +58,8 @@ func loadConfig() (*config, error) {
}
timeoutStr := strings.TrimSpace(os.Getenv("MTPROXY_CHECK_TIMEOUT"))
if timeoutStr == "" {
timeoutStr = "15s"
// Fake-TLS + drain + req_pq/resPQ к DC часто >15s на медленных линиях и при многих прокси подряд.
timeoutStr = "45s"
}
checkTimeout, err := time.ParseDuration(timeoutStr)
if err != nil || checkTimeout <= 0 {
+1 -1
View File
@@ -12,7 +12,7 @@ services:
MTPROXY_LIST_FILE: /data/proxies.txt
MTPROXY_CHECK_INTERVAL: 5m
MTPROXY_HTTP_ADDR: ":8080"
MTPROXY_CHECK_TIMEOUT: 15s
MTPROXY_CHECK_TIMEOUT: 45s
MTPROXY_DC_ID: "2"
# Опционально: только перечисленные IP/CIDR (иначе не задавайте переменную)
# MTPROXY_ALLOWED_IPS: "172.17.0.0/16,127.0.0.1"
+1 -1
View File
@@ -49,7 +49,7 @@ docker run -d --name mtproxy-api --restart unless-stopped -p 8080:8080 `
| `MTPROXY_LIST_FILE` | `/data/proxies.txt` | Путь к файлу: одна `tg://` ссылка на строку; пустые строки и строки с `#` в начале пропускаются |
| `MTPROXY_CHECK_INTERVAL` | `5m` | Интервал между циклами (`time.ParseDuration`, например `5m`, `1h`) |
| `MTPROXY_HTTP_ADDR` | `:8080` | Адрес прослушивания HTTP |
| `MTPROXY_CHECK_TIMEOUT` | `15s` | Таймаут одной проверки (аналог `-timeout` CLI) |
| `MTPROXY_CHECK_TIMEOUT` | `45s` (в демоне по умолчанию; CLI по-прежнему `15s` если не задано) | Таймаут **всей** одной проверки: TCP + Fake-TLS + MTProxy init + drain + `req_pq`/`resPQ` до DC; при медленной сети увеличьте |
| `MTPROXY_DC_ID` | `2` | DC id (аналог `-dc-id` CLI) |
| `MTPROXY_ALLOWED_IPS` | *(не задана)* | Если задана непустая строка — доступ к **всем** маршрутам только с перечисленных IP/CIDR; остальные получают **403** и JSON `{"error":"forbidden"}`. Формат: через запятую, пробелы допускаются: `192.168.1.10`, `10.0.0.0/8`, IPv6 и CIDR вида `2001:db8::/32`. Учитывается только **`RemoteAddr`** TCP-соединения; заголовок `X-Forwarded-For` **не** используется |
+5
View File
@@ -3,6 +3,7 @@ package checkresult
import (
"context"
"errors"
"net"
"mtproxy_checker/internal/checker"
)
@@ -18,5 +19,9 @@ func Classify(err error) (exitCode int, message string) {
if errors.Is(err, context.DeadlineExceeded) {
return 4, "timeout"
}
var ne net.Error
if errors.As(err, &ne) && ne.Timeout() {
return 4, "timeout"
}
return 1, err.Error()
}
+16 -3
View File
@@ -113,6 +113,9 @@ func isResPQ(mtInner []byte) bool {
// Consumes 0x17 payloads with dec so the CTR stream stays aligned with the server; discards MTProto frames until idle.
func DrainPostInitEE(ctx context.Context, br *bufio.Reader, conn net.Conn, dec cipher.Stream, maxWait time.Duration) error {
end := time.Now().Add(maxWait)
if d, ok := ctx.Deadline(); ok && d.Before(end) {
end = d
}
var acc []byte
const maxDrain = 256 << 10
drained := 0
@@ -122,10 +125,15 @@ func DrainPostInitEE(ctx context.Context, br *bufio.Reader, conn net.Conn, dec c
return ctx.Err()
default:
}
d := 200 * time.Millisecond
d := 500 * time.Millisecond
if rem := time.Until(end); rem < d {
d = rem
}
if cd, ok := ctx.Deadline(); ok {
if rem := time.Until(cd); rem < d {
d = rem
}
}
if d <= 0 {
return nil
}
@@ -185,22 +193,27 @@ func VerifyResPQ(ctx context.Context, conn net.Conn, enc, dec cipher.Stream, tls
deadline, ok := ctx.Deadline()
if !ok {
deadline = time.Now().Add(15 * time.Second)
deadline = time.Now().Add(60 * time.Second)
}
var acc []byte
const maxAcc = 256 << 10
// Один read ждёт ответ DC; 3s мало при нагрузке/гео — держим до 30s, но не дольше ctx.
const perReadSlack = 30 * time.Second
for time.Now().Before(deadline) {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
chunkDeadline := time.Now().Add(3 * time.Second)
chunkDeadline := time.Now().Add(perReadSlack)
if chunkDeadline.After(deadline) {
chunkDeadline = deadline
}
if !chunkDeadline.After(time.Now().Add(50 * time.Millisecond)) {
return fmt.Errorf("%w: not enough time left waiting for resPQ", context.DeadlineExceeded)
}
_ = conn.SetReadDeadline(chunkDeadline)
var chunk []byte
var rerr error