Powrót do strony głównej

10 błędów config management w production

Artykuł analizuje 10 błędów zarządzania konfiguracją aplikacji na podstawie rzeczywistych projektów. Od hardkodu parametrów po brak dokumentacji — jak uniknąć awarii na prodzie. Przykłady kodu i rekomendacje dla senior deweloperów.

Top-10 błędów konfiguracji aplikacji na prodzie
Advertisement 728x90

Zarządzanie konfiguracją aplikacji: 10 typowych błędów w środowisku produkcyjnym

Niepoprawne limity czasu, tajne dane lub ograniczenia w konfiguracji powodują awarie szybciej niż błędy w logice aplikacji. W przeciwieństwie do kodu źródłowego, konfiguracje często omijają przeglądy kodu (code review), testy oraz potok CI. To tworzy ryzyko: usługa zapisuje dane do niewłaściwej bazy danych, wyczerpuje pulę połączeń lub ujawnia poufne dane. Analiza rzeczywistych projektów wykazała 10 błędów, które pozostają ukryte aż do wystąpienia incydentu.

Hardkodowanie limitów czasu: ponad 30 miejsc w kodzie

Limity czasu zakodowane w źródle wymagają ponownej kompilacji przy każdej zmianie. Wyszukiwanie frazy Duration.ofSeconds wykazało ponad 30 przypadków z różnymi wartościami: 10 s w NotificationService, 30 s w SearchService, 15 s w ApiRoutes.

private static final Duration TIMEOUT = Duration.ofSeconds(10);  // NotificationService
private static final Duration TIMEOUT = Duration.ofSeconds(30);  // SearchService
private static final Duration TIMEOUT = Duration.ofSeconds(10);  // AuthFilter
private static final Duration TIMEOUT = Duration.ofSeconds(15);  // ApiRoutes

Pod obciążeniem prawidłowa konfiguracja limitów czasu jest krytyczna, ale hardkod uniemożliwia elastyczność. Rozwiązanie: przeniesienie do pliku konfiguracyjnego z możliwością nadpisania przez zmienne środowiskowe.

Google AdInline article slot

Brak walidacji: kasowanie bazy danych produkcyjnej

Obiekt konfiguracyjny o długości 695 linii sprawdza tylko jeden parametr. Pozostałe są akceptowane bez żadnych ograniczeń: rozmiar puli = 0, limit czasu = -1, pusty adres URL bazy danych.

String authType = config.getString("authType");
if (!Set.of("kerberos", "jwt").contains(authType)) {
    throw new IllegalArgumentException("Nieprawidłowy typ uwierzytelnienia. Dopuszczalne wartości to: kerberos, jwt");
}

Niebezpieczny przykład: http.server.parsing.max-content-length = 10g — pojedynczy żądanie zużywa 10 GB pamięci RAM. Flaga dropAll = ${?DROP_ALL} dla Liquibase kasuje całą schemę bazy danych bez potwierdzenia. Mechanizm fail-fast podczas uruchamiania aplikacji zapobiega incydentom.

Wartości domyślne maskują problemy

Wartości domyślne ukrywają brak kluczy konfiguracyjnych aż do momentu uruchomienia aplikacji. Przy włączaniu SSO:

Google AdInline article slot
Duration maxResponseDelay = ssoEnabled
    ? config.getDuration("sso.maxResponseDelay")
    : Duration.ofMinutes(10);
long responseCacheSize = ssoEnabled
    ? config.getLong("sso.responseCacheSize")
    : 10_000;

Brak kluczy powoduje awarię w środowisku produkcyjnym. Podobnie wartość tokenTtl: skonfigurowana jako 1 minuta nieoczekiwanie staje się 3 minutami bez wpisu w logach, co narusza zasady bezpieczeństwa.

  • Problem wartości domyślnych: ukrywają błędne ustawienia aż do aktywacji funkcji.
  • Rozwiązanie: walidacja podczas uruchamiania oraz ostrzeżenia przy użyciu wartości domyślnej.

Rozbieżności konfiguracji między środowiskiem testowym a produkcyjnym

Konfiguracja testowa różni się od produkcyjnej o kilka rzędów wielkości:

| Parametr | Produkcja | Test |

Google AdInline article slot

|----------|-----------|------|

| api.responseLimit | 10 MB | 1 GB |

| api.contextLimit | 10 MB | 1 MB |

Odpowiedź o rozmiarze 50 MB przejdzie testy, ale spowoduje awarię w produkcji. Odwrotna sytuacja: testy są zbyt restrykcyjne i generują fałszywe wyniki negatywne.

Chaos w nazewnictwie parametrów

Jeden plik application.conf miesza różne style:

fileStoragePath = "/opt/storage"          # camelCase
retention-days = 7                        # kebab-case
createdump-interval-seconds = 240         # hybryda
usage-threshold = 80                      # kebab-case
compressHeapDump = true                   # camelCase

Flagi logiczne: sslValidationEnabled, smtpSslEnable, saml.enabled, isUseSecureCookieJWT. Nadpisywanie przez zmienne środowiskowe nie działa: smtpSslEnableSMTP_SSL_ENABLED (różnica między Enable a Enabled).

  • Mieszanie camelCase i kebab-case w jednym pliku.
  • Niezgodność między składnią HOCON a konwencją nazewnictwa zmiennych środowiskowych.
  • Cztery różne konwencje nazewnictwa flag logicznych.

Martwe flagi funkcji bez cyklu życia

16 flag funkcji w klasie konfiguracyjnej: ws-cache-enabled=false wszędzie, history-import-enabled=true zawsze. Brak dat, autorów ani uzasadnienia — rośnie obciążenie poznawcze.

  • Dodaj: datę, autora, uzasadnienie i termin usunięcia.
  • Usuń „nieśmiertelne” flagi: zawsze true/false, nieużywane w kodzie.

Niepoprawna kolejność nadpisywania w HOCON

W HOCON decyduje ostatnia przypisana wartość. Poprawnie:

key = "default-value"
key = ${?ENV_OVERRIDE}

Błąd:

dump {
  enabled = ${?DUMP_ENABLED}
  enabled = false
  directory = ${?DUMP_DIR}
  directory = "opt/myapp/dumps/auto"
}

Zmienna środowiskowa zostaje nadpisana przez false — zrzuty nie są włączone.

Konfiguracja bez dokumentacji: ponad 100 parametrów

Plik docker.md zawiera listę zmiennych środowiskowych bez opisów: EMAIL_ENABLED=false/true. Klasa AppConfig.java ma 695 linii bez komentarzy Javadoc. Parametr sync-request-timeout-seconds=600 — do czego służy? workflowStepLimit=200 — jakie są konsekwencje ustawienia 0 lub 100 000?

Hardkod zewnętrznych adresów URL i poziomów logowania

Adresy URL API zakodowane w źródle wymagają ponownej kompilacji przy zmianie punktu końcowego. Poziom logowania w obrazie Docker wymaga montowania woluminu lub ponownej budowy obrazu, aby włączyć tryb DEBUG.

Na co zwrócić uwagę:

  • Wszystkie parametry przenieść do konfiguracji z walidacją podczas uruchamiania.
  • Jednolity styl nazewnictwa dla HOCON i zmiennych środowiskowych.
  • Dokumentacja każdego parametru: typ, zakres dopuszczalnych wartości, wartość domyślna, cel użycia.
  • Fail-fast zamiast cichego stosowania wartości domyślnej.
  • Cykl życia flag funkcji: data dodania, uzasadnienie i termin usunięcia.

— Editorial Team

Advertisement 728x90

Czytaj dalej