Обработка ошибок Go SDK и восстановление прерванных задач
Тайм-аут не означает, что создать задачу не удалось. Сохраняйте исходные входные данные задачи и ID запроса SDK. Если у вас есть ID задачи, возобновите работу через GetTask; иначе повторите CreateTask с точно теми же исходными входными данными и тем же ID запроса.
Отмена прекращает ожидание в Go-клиенте, но не удалённую задачу. Восстановите эту задачу, прежде чем платить за новое решение.
На этой странице
Запустите пример обработки ошибок
Используйте Go 1.22 или новее с официальным модулем solvethree.com/sdk версии v0.1.0. Инструкции по настройке см. в руководстве по интеграции с Go.
Задайте серверные переменные окружения SOLVETHREE_API_KEY и SOLVETHREE_PROXY. Замените Site и Action из примера на имя целевого хоста и действие. Для сайта нужен активный профиль в рабочем пространстве; передача имени хоста не создаёт профиль. Этот запрос reCAPTCHA использует один прокси и не требует Type или URL.
package main
import (
"context"
"fmt"
"errors"
"log"
"os"
"time"
solvethree "solvethree.com/sdk"
)
func main() {
client, err := solvethree.NewClient(os.Getenv("SOLVETHREE_API_KEY"), nil)
if err != nil { log.Fatal(err) }
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
input := solvethree.TaskRequest{Site: "accounts.example.com", Action: "login", Proxy: os.Getenv("SOLVETHREE_PROXY")}
result, err := client.Solve(ctx, input, solvethree.SolveOptions{})
if err != nil {
var failed *solvethree.TaskFailedError
var api *solvethree.APIError
var recovery *solvethree.Error
switch {
case errors.As(err, &failed):
log.Printf("Failed task %s: %s", failed.TaskID, failed.ErrorCode)
case errors.As(err, &recovery):
log.Printf("Recovery request=%s task=%s", recovery.RequestID, recovery.TaskID)
if errors.As(err, &api) { log.Printf("HTTP %d; retry delay %s", api.StatusCode, api.RetryAfter) }
// Save input plus recovery.RequestID. Resume GetTask for a known TaskID;
// otherwise replay CreateTask with identical inputs and that RequestID.
}
return
}
fmt.Println("Ready task:", result.ID)
// Submit result.Solution.Token with its browser identity and original proxy.
}В примере задаётся срок действия контекста в 180 секунд, а ID для восстановления записываются в журнал, когда ошибка SDK их предоставляет. Запись в журнал не обеспечивает надёжного восстановления: сохраните исходный input, возвращённый RequestID и любой доступный TaskID, прежде чем отбросить ошибку.
«Готовая задача» означает, что решение доступно, а не что целевой сайт его принял. SDK не отправляет его за вас. Отправьте Solution.Token, используя возвращённые данные браузера и, для этого примера с одним прокси, исходный прокси.
Отличайте сбой задачи от прерванного запроса
Проверяйте обёрнутые ошибки с помощью errors.As, а отмену — с помощью errors.Is. Эти проверки отвечают на разные вопросы: одна ошибка может содержать ID для восстановления, оборачивать HTTP-ошибку и при этом требовать обработки как прерванная операция.
| Проверка | Значение и дальнейшие действия |
|---|---|
errors.As для *solvethree.TaskFailedError | Задача завершилась с окончательной ошибкой. Прочитайте TaskID, RequestID и ErrorCode. Получите завершившуюся с ошибкой задачу через GetTask, чтобы прочитать текст её Error, затем прекратите опрос этой задачи. Не отправляйте вслепую неизменённые входные данные повторно. |
errors.Is для context.DeadlineExceeded или context.Canceled | Вызывающая сторона прекратила ожидание. Это не позволяет установить, удалось ли создание и завершилась ли удалённая задача. Сохраните информацию для восстановления и при необходимости возобновите работу с новым контекстом. |
errors.As для *solvethree.Error | Обёртка SDK предоставляет RequestID и TaskID и оборачивает исходную причину Cause. Сохраните ID вместе с точными исходными входными данными. |
errors.As для *solvethree.APIError | Проверьте HTTP-код StatusCode и длительность RetryAfter. HTTP-ошибка отличается от задачи со статусом failed; не считайте, что получили корректные данные задачи. |
В примере вложенная APIError проверяется в ветке восстановления. Проверяйте отмену отдельно через errors.Is, если приложению нужно отличать истечение срока от явной отмены.
Solve создаёт задачу один раз. Он повторяет только опрос при временных ответах HTTP 429, 502, 503 или 504, соблюдая Retry-After в пределах срока действия контекста. CreateTask никогда не повторяет свой POST автоматически.
Возобновите работу с существующей задачей
- 1.
Сохраняйте исходный запрос без изменений
Сохраните все входные данные задачи, включая прокси или список кандидатов, вместе с ID запроса. CreateTask генерирует ID запроса, если вы его не указали; сохраните сгенерированное значение, доступное в ошибке для восстановления. Не воссоздавайте запрос позднее из конфигурации, которая могла измениться.
- 2.
Используйте GetTask, если знаете ID задачи
Создайте новый контекст, если срок действия старого истёк или он был отменён, затем получите задачу по сохранённому TaskID через GetTask. Продолжайте ожидание при статусах pending или solving, используйте решение только при ready и прекращайте ожидание при failed.
- 3.
Повторяйте создание только тогда, когда ID задачи неизвестен
Задайте в RequestID сохранённого исходного TaskRequest восстановленный ID запроса, затем вызовите CreateTask с теми же входными данными. Повторное использование того же ID и запроса возвращает существующую задачу. Изменение входных данных при повторном использовании этого ID вызывает конфликт.
Не используйте новый ID запроса только потому, что истекло время ожидания соединения. Это запускает новую логическую задачу, а не восстанавливает задачу с неизвестным результатом. Сначала выясните, что произошло с исходной задачей; если она завершилась с ошибкой, изучите её, прежде чем решать, нужен ли исправленный запрос.
Источники и справочник API
Запустите первую задачу.
Начните с $5 на балансе рабочего пространства.