>_ DevTrendspl

Język

Strona główna

Języki

Sekcje

Frontend Backend Mobilne DevOps AI / ML GameDev Blockchain Bezpieczeństwo
Rust

Jak przestać naprawiać systemy rozproszone i zacząć żyć z Restate

4112 gwiazdki

Wyobraź sobie taką sytuację: piszesz mikroserwis do przetwarzania płatności. W połowie procesu sieć zawodzi, baza danych przekracza limit czasu, albo kontener po prostu restartuje się. Co dzieje się z transakcją? W klasycznym scenariuszu musisz ręcznie zaimplementować logikę ponawiania, śledzić idempotentność, konfigurować kolejki wiadomości, a najprawdopodobniej wprowadzić jakąś złożoną sagę. To bolesne, czasochłonne i zamienia Twój kod w labirynt obsługi błędów.

Niedawno odkryłem Restate, projekt rozwiązujący ten problem na poziomie infrastruktury. Deweloperzy nazywają to „Durable Execution" — odporne na błędy wykonywanie kodu. Idea jest taka, że Twój kod staje się nieśmiertelny: jeśli proces ulegnie awarii, Restate wznawia go dokładnie w miejscu, w którym się zatrzymał, zachowując wszystkie zmienne i stan.

Restate overview

Co to w ogóle jest

Restate to binarny plik w Rust, który działa jako serwer proxy i koordynator dla Twoich usług. Przejmuje całą brudną robotę związaną z zarządzaniem stanem i wywołaniami. Piszesz zwykły kod w TypeScript, Python lub Go, używasz SDK i nagle Twoje funkcje zamieniają się w niezawodne przepływy pracy.

Główna różnica w porównaniu z ciężkimi rozwiązaniami jak Temporal polega na tym, że Restate jest znacznie łatwiejszy do rozpoczęcia pracy. Nie potrzebujesz masywnej konfiguracji z bazami danych i złożonymi workerami. Możesz po prostu uruchomić pojedynczy plik binarny lub kontener Docker i zacząć pracę.

Jak Restate pomaga w praktyce

Projekt zawiera kilka ciekawych koncepcji, które naprawdę upraszczają życie.

Gwarantowane wykonanie

Jeśli wywołałeś funkcję przez Restate, wykona się ona do końca. Kropka. Jeśli serwer z Twoim kodem ulegnie awarii, Restate poczeka na jego powrót i kontynuuje wykonanie od ostatniego pomyślnego kroku. Nie musisz się już martwić o to, czy email został wysłany do użytkownika dwukrotnie lub czy pieniądze zostały pobrane dwukrotnie.

Inteligentne timery i obietnice

Zwykle implementacja opóźnienia w systemie rozproszonym to quest. Musisz umieścić wiadomość w kolejce z opóźnieniem lub skonfigurować zadanie cron. W Restate po prostu piszesz ctx.sleep(duration). Wątek nie blokuje się bezcelowo: usługa może się całkowicie wyłączyć, a trzy dni później Restate ją „obudzi" i kontynuuje wykonanie.

Stan bezpośrednio w kodzie

Restate pozwala przechowywać stan K/V powiązany z konkretną encją (na przykład ID użytkownika). Wygląda to jak zwykła praca z obiektami, ale pod maską Restate gwarantuje, że dane są spójne i zawsze dostępne wraz z żądaniem. Jest to szczególnie wygodne dla architektur serverless, gdzie funkcje typowo nie mają pamięci.

Jak to wygląda w kodzie

Powiedzmy, że musimy zaimplementować proces rejestracji użytkownika z potwierdzeniem emailem. W TypeScript z użyciem Restate SDK wyglądałoby to mniej więcej tak:

import * as restate from "@restatedev/restate-sdk";

const userService = restate.service({
  name: "users",
  handlers: {
    register: async (ctx: restate.Context, user: { id: string, email: string }) => {
      // Сохраняем состояние
      ctx.set("status", "pending");

      // Отправляем письмо (Restate гарантирует, что это случится 1 раз)
      await ctx.run(() => sendWelcomeEmail(user.email));

      // Ждем подтверждения или таймаута в 24 часа
      const confirmed = await ctx.awakeable<boolean>("email-confirmed");
      
      if (confirmed) {
        ctx.set("status", "active");
      }
    }
  }
});

Tutaj ctx.run gwarantuje, że efekt uboczny (wysłanie emaila) wykona się pomyślnie, a wynik zostanie zbuforowany. Jeśli funkcja ulegnie awarii po wysłaniu, przy restarcie Restate po prostu pomija ten krok, wiedząc że jest już wykonane.

Strona techniczna

Projekt jest napisany w Rust, co daje doskonałą wydajność. Architektonicznie Restate działa jako invoker. Odbiera przychodzące żądania przez HTTP/gRPC, zapisuje je do swojego logu i wywołuje Twoje handlery.

Ciekawe jest to, że Restate może „zawieszać" wykonanie. Jeśli Twój kod czeka na odpowiedź z zewnętrznego API lub timera, Restate zwalnia zasoby. Gdy nastąpi zdarzenie, przywraca kontekst wykonania. Pozwala to na uruchamianie tysięcy długotrwałych procesów na skromnym sprzęcie.

Kto powinien spróbować

Restate idealnie wypełni luki w projektach, gdzie:

  • Jest wiele łańcuchów wywołań między mikroserwisami.
  • Musisz budować złożone łańcuchy działań (sagi, przepływy pracy).
  • Używasz agentów AI, którzy muszą długo czekać na odpowiedzi LLM i zachować kontekst rozmowy.
  • Istnieją zadania z opóźnionym wykonaniem (przypomnienie o porzuconym koszyku za 2 godziny).

Projekt jest aktywnie rozwijany, z niemal 4 000 gwiazdek na GitHub. SDK są dostępne dla TypeScript/JavaScript, Java/Kotlin, Python, Go i Rust.

Oczywiście nie powinieneś się spieszyć, żeby jutro wciągać nowy komponent infrastruktury do produkcji dużego banku — najpierw musisz wypróbować lokalnie. Ale dla startupów lub nowych funkcji w istniejących projektach może zaoszczędzić tygodnie developmentu.

Możesz wypróbować dosłownie w kilka minut:

brew install restatedev/tap/restate-server
restate-server

I to wszystko, masz lokalne środowisko do uruchamiania aplikacji odpornych na błędy. Być może to obecnie najniższy próg wejścia do świata Durable Execution.

Powiązane projekty