{"id":31622886,"url":"https://github.com/simplegear/kernel","last_synced_at":"2026-04-29T16:32:54.367Z","repository":{"id":313377572,"uuid":"1043150573","full_name":"simplegear/kernel","owner":"simplegear","description":"A production-ready toolkit for Go services: a cohesive app runtime with prioritized graceful shutdown, Redis-based leader election, a periodic job scheduler, and a readiness barrier. Includes HTTP/chi and gRPC servers, pgx-powered Postgres and ClickHouse wrappers, and structured logging via zap.","archived":false,"fork":false,"pushed_at":"2025-09-05T15:57:56.000Z","size":39,"stargazers_count":0,"open_issues_count":13,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-06T17:49:48.430Z","etag":null,"topics":["application-framework","concurrency","distributed-lock","go","golang","graceful-shutdown","grpc","http","job-scheduler","leader-election","library","microservices","observability","readiness","redis","resilience","scheduler","service-runtime","toolkit"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simplegear.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-23T08:43:35.000Z","updated_at":"2025-09-29T06:02:11.000Z","dependencies_parsed_at":"2025-09-05T17:51:25.556Z","dependency_job_id":"9565cd06-555a-40d2-89a1-5b5261a0886b","html_url":"https://github.com/simplegear/kernel","commit_stats":null,"previous_names":["pavelagarkov/kernel","simplegear/kernel"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/simplegear/kernel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplegear%2Fkernel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplegear%2Fkernel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplegear%2Fkernel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplegear%2Fkernel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simplegear","download_url":"https://codeload.github.com/simplegear/kernel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplegear%2Fkernel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32434822,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T13:34:34.882Z","status":"ssl_error","status_checked_at":"2026-04-29T13:34:29.830Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["application-framework","concurrency","distributed-lock","go","golang","graceful-shutdown","grpc","http","job-scheduler","leader-election","library","microservices","observability","readiness","redis","resilience","scheduler","service-runtime","toolkit"],"created_at":"2025-10-06T17:37:04.766Z","updated_at":"2026-04-29T16:32:54.361Z","avatar_url":"https://github.com/simplegear.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kernel\n\nНабор утилит и мини‑фреймворков для сервисов на Go: аккуратный каркас приложения (graceful shutdown, обработка сигналов, рекавери), лидер‑элекция через Redis, планировщик задач, барьер готовности, обёртки для PostgreSQL и ClickHouse, HTTP (chi) и gRPC серверы с полезными мидлварами, логирование на базе zap, простые утилиты.\n\n\u003e Цель — ускорить запуск продуктивных сервисов: «сшить» инфраструктурные куски в согласованный рантайм с безопасной остановкой и понятными контрактами.\n\n---\n\n## Содержание\n- [Возможности](#возможности)\n- [Установка](#установка)\n- [Требования](#требования)\n- [Быстрый старт](#быстрый-старт)\n- [Архитектура пакетов](#архитектура-пакетов)\n    - [application](#application)\n    - [watchdog (leader election)](#watchdog-leader-election)\n    - [scheduler](#scheduler)\n    - [readiness_barrier](#readiness_barrier)\n    - [database/postgres](#databasepostgres)\n    - [database/clickhouse](#databaseclickhouse)\n    - [locker (Redis‑lock)](#locker-redislock)\n    - [server/http (chi)](#serverhttp-chi)\n    - [server/grpc](#servergrpc)\n    - [logger](#logger)\n    - [utils](#utils)\n- [Рекомендации по эксплуатации](#рекомендации-по-эксплуатации)\n- [Дорожная карта](#дорожная-карта)\n- [Лицензия](#лицензия)\n\n---\n\n## Возможности\n- **Единая точка входа приложения**: управление сигналами ОС (SIGTERM/SIGINT/SIGQUIT), список shutdown‑хуков с приоритетами, рекавери паник.\n- **Лидер‑элекция** (Redis): надёжный цикл захвата/продления блокировки, уведомления о потере/получении лидерства.\n- **Планировщик задач**: периодические job’ы c rate‑лимитом, дедлайнами и двумя режимами остановки (немедленная/мягкая).\n- **Барьер готовности**: переключение ready/not‑ready по сигналам, безопасный жизненный цикл.\n- **PostgreSQL (pgxpool)**: обёртка с явной настройкой Min/MaxConns, TTL/idle, health‑check, application_name.\n- **ClickHouse**: подключение с LZ4, политика `NeedReconnect/NeedWait` по ошибкам, безопасный reconnect.\n- **HTTP (chi)**: мидлвары для логов, X‑Correlation‑ID, recover; аккуратный graceful shutdown.\n- **gRPC**: сервер + interceptors (panic → Internal, лимит размера ответа, таймауты), reflection по флагу.\n- **Логирование (zap)**: унифицированные `WriteInfoLog/WriteWarnLog/WriteErrorLog/WriteFatalLog`.\n\n## Установка\n```bash\ngo get github.com/PavelAgarkov/kernel@latest\n```\n\n## Требования\n- Go **1.23+** (модуль объявлен как `go 1.23.1`)\n- Redis (для лидер‑элекции), PostgreSQL/ClickHouse — при использовании соответствующих пакетов\n\n---\n\n## Быстрый старт\nНиже — минимальный каркас сервиса на базе **application**, **server**, **scheduler** и **watchdog**.\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"time\"\n    \"net/http\"\n\n    apppkg \"github.com/PavelAgarkov/kernel/application\"\n    logtypes \"github.com/PavelAgarkov/kernel/logger\"\n    logger \"github.com/PavelAgarkov/kernel/logger/zap_engine\"\n    \"github.com/PavelAgarkov/kernel/scheduler\"\n    \"github.com/PavelAgarkov/kernel/server\"\n    \"github.com/PavelAgarkov/kernel/watchdog\"\n    \"github.com/PavelAgarkov/kernel/locker\"\n\n    \"github.com/go-redis/redis/v8\"\n)\n\nfunc main() {\n    // базовый ctx со стопом\n    ctx, cancel := context.WithCancel(context.Background())\n\n    // инициализация рантайма приложения (ядро)\n    app := apppkg.NewApp(ctx, /*GOMAXPROCS*/ 0, /*GC%*/ 100)\n    defer app.FlushLogger()\n    defer app.RegisterRecovers()()\n\n    // HTTP сервер на chi (опционально)\n    httpStop := server.CreateHTTPChiServer(func(s *server.HTTPServerChi) {\n        s.Router.Use(server.RecoverChiMiddleware, server.LoggingChiMiddleware)\n        s.Router.Get(\"/health\", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) })\n    }, \":8080\")\n    app.RegisterShutdown(\"http\", httpStop, apppkg.HighPriority)\n\n    // Планировщик с одной задачей\n    sch := scheduler.NewJobScheduler(1)\n    _ = sch.Add(scheduler.JobConfiguration{\n        Name:     \"heartbeat\",\n        Tick:     5 * time.Second,\n        Deadline: 2 * time.Second,\n        StopMode: scheduler.StopImmediate,\n        Func: func(ctx context.Context) error {\n            logger.WriteInfoLog(ctx, \u0026logtypes.LogEntry{Msg: \"tick\"})\n            return nil\n        },\n    })\n    app.RegisterShutdown(\"scheduler\", scheduler.NewTaskSupervisor([]scheduler.JobSchedulerInterface{sch}).Stop(), apppkg.MediumPriority)\n\n    // Лидер‑элекция (при необходимости)\n    rdb := redis.NewClient(\u0026redis.Options{Addr: \"127.0.0.1:6379\"})\n    lck := locker.NewLocker(rdb)\n    wd := watchdog.NewRedisWatchdogLeader(ctx, lck)\n\n    app.RegisterWatchdogsLeadership(\u0026apppkg.LeaderSupervisor{\n        Watchdog:       wd,\n        Watcher:        wd.Elect(watchdog.Config{ElectionName: watchdog.Cron}),\n        SupervisorName: \"cron-supervisor\",\n        Start: func() { sch.Start(ctx)() },\n        Stop:  func() { sch.Stop()() },\n    })\n\n    // обработчик сигналов ОС\n    app.Start(cancel)\n\n    // блокировка до остановки\n    app.Run()\n}\n```\n\n---\n\n## Архитектура пакетов\n\n### application\nКаркас приложения: обработка сигналов ОС, приоритезированные shutdown‑хуки, рекавери, и «надсмотрщики» над задачами, зависящими от лидер‑элекции.\n\n**Ключевые сущности:**\n- `App` — ядро;\n    - `RegisterShutdown(name string, fn func(), priority int)` — регистрирует действие на остановку. Чем **меньше** число, тем **выше** приоритет (выполняется раньше).\n    - `Start(cancel context.CancelFunc)` — подписка на SIGTERM/SIGINT/SIGQUIT; по сигналу вызывает `cancel()`.\n    - `Run()` — ждёт завершения базового контекста.\n    - `RegisterWatchdogsLeadership(*LeaderSupervisor)` — связывает лидер‑элекцию с `Start/Stop` функций над подсистемами.\n- `LeaderSupervisor` — привязывает `watchdog` к конкретной подсистеме: при `TakenAcquire` вызывает `Start()`, при `LostAcquire` — `Stop()`.\n\n\u003e Используется односвязный список для shutdown‑хуков, упорядоченных по приоритетам.\n\n### watchdog (leader election)\nЛидер‑элекция на Redis‑блокировке:\n- `RedisWatchdogLeader` периодически пытается захватить/продлить `key`, шлёт события в канал наблюдателю.\n- События: `TakenAcquire` (стали лидером), `LostAcquire` (потеряли лидерство).\n\n**Пример:**\n```go\nwd := watchdog.NewRedisWatchdogLeader(ctx, locker)\nch := wd.Elect(watchdog.Config{ElectionName: \"my-job\", Expiration: 30*time.Second})\nfor ev := range ch { /* переключаем подсистемы */ }\n```\n\n### scheduler\nПланировщик периодических задач с rate‑лимитом и дедлайнами.\n\n- `Add(JobConfiguration)` до `Start`.\n- `Start(ctx)()` запускает задачи (каждая — в собственной горутине через Ticker).\n- `Stop()()` останавливает: отменяет контексты, гасит тикеры и ждёт `WaitGroup`.\n- `StopMode`:\n    - `StopImmediate` — задача наследует общий `ctx`; при остановке мгновенно отменяется.\n    - `StopGraceful` — задача получает `context.Background()` с таймаутом, чтобы корректно доработать цикл.\n\n### readiness_barrier\nЛёгкий флаг готовности сервиса:\n- `Start/Stop` — безопасный запуск/остановка фонового слушателя сигналов без гонок.\n- `SendSignalCtx(ctx, ReadySignalToggle|NotReadySignalToggle)` — выставить состояние.\n- `IsReady()` — атомарное чтение состояния.\n\n### database/postgres\nОбёртка над `pgxpool.Pool` с продуманными настройками:\n- `MaxConns/MinConns`, `MaxConnIdleTime`, `MaxConnLifetime` (+ `Jitter`), `HealthCheckPeriod`, `ConnectTimeout`.\n- `application_name` в `RuntimeParams` для удобной диагностики.\n\n```go\ncfg := postgres.Configs{ Host: \"db\", Port: \"5432\", Username: \"u\", Password: \"p\", Database: \"app\",\n    SSLMode: \"disable\", MaxOpenedConnections: 20,\n    ConnectionMaxIdleTime: 5*time.Minute, ConnectionMaxLifeTime: 1*time.Hour,\n    HealthCheckPeriod: 15*time.Second, ConnectTimeout: 1*time.Second,\n}\npg := postgres.NewPostgresConnection(ctx, cfg)\ndefer pg.Stop()\npool := pg.GetPool()\n```\n\n### database/clickhouse\nПодключение и политика обработки ошибок для CH:\n- Настройка пула (`MaxOpen/Idle`, TTL, Lifetime), LZ4, `DialTimeout`.\n- `NeedReconnect(error) (bool, *ch.Exception)` — классификация ошибок, при которых разумно пересоздавать соединение.\n- `NeedWait(error) (bool, time.Duration, *ch.Exception)` — когда полезна задержка (квоты, «мало живых реплик», перегруз).\n- Безопасный `Reconnect(ctx, newCfg)` с обменом `*sql.DB` под мьютексом.\n\n### locker (Redis‑lock)\nПростейшая распределённая блокировка на Lua‑скриптах `SET NX PX`/`DEL`/`PEXPIRE`:\n- `Lock(ctx, key, value, TTL)`\n- `Unlock(ctx, key, value)`\n- `ExtendLockTTL(ctx, key, value, TTL)`\n\n### server/http (chi)\nУпаковка для быстрого старта HTTP‑сервера:\n- `CreateHTTPChiServer(routes, port, ...middleware) func()` возвращает **функцию остановки** (graceful 5s).\n- Мидлвары: `RecoverChiMiddleware` (panic → 500), `LoggingChiMiddleware` (X‑Correlation‑ID + лог), `LoggerChiContextMiddleware`.\n\n```go\nstop := server.CreateHTTPChiServer(func(s *server.HTTPServerChi){\n    s.Router.Use(server.RecoverChiMiddleware, server.LoggingChiMiddleware)\n    s.Router.Get(\"/ping\", func(w http.ResponseWriter, r *http.Request){ w.Write([]byte(\"pong\")) })\n}, \":8080\")\n// ...\nstop() // при остановке приложения\n```\n\n### server/grpc\ngRPC сервер с полезными перехватчиками:\n- `CreateGRPCServer(ctx, register, Configs{Port, Network, Reflection}, opts...) func()` — возвращает **shutdown**.\n- Interceptors:\n    - `PanicHandler` → код `Internal` + стек.\n    - `EnforceMaxSendSize(maxBytes)` — жёсткий лимит ответа (избегает утечек при гигантских ответах).\n    - `TimeoutUnaryInterceptor(d)` — таймаут на запрос.\n\n```go\nshutdown := server.CreateGRPCServer(ctx, func(s *grpc.Server){\n    // pb.RegisterYourServiceServer(s, impl)\n}, server.Configs{Port: \":9090\", Network: \"tcp\", Reflection: true},\n   grpc.ChainUnaryInterceptor(\n       server.TimeoutUnaryInterceptor(3*time.Second),\n   ),\n)\n// ...\nshutdown()\n```\n\n### logger\nДве части:\n- `logger` — типы записей (`LogEntry` и др.).\n- `logger/zap_engine` — функции `WriteInfoLog/WriteWarnLog/WriteErrorLog/WriteFatalLog`, `FlushLogs()`.\n\n```go\nimport (\n  logtypes \"github.com/PavelAgarkov/kernel/logger\"\n  logger   \"github.com/PavelAgarkov/kernel/logger/zap_engine\"\n)\nlogger.WriteInfoLog(ctx, \u0026logtypes.LogEntry{Msg: \"hello\", Component: \"app\", Method: \"main\"})\n```\n\n### utils\nМелкие утилиты: безопасный запуск горутин с recover (`GoRecover`), контексты с тайм‑аутом без дедлайна, хелперы по слайсам и пр.\n\n---\n\n## Рекомендации по эксплуатации\n- **Приоритеты shutdown**: сначала закрывайте внешние интерфейсы (HTTP/gRPC), затем фоновые воркеры и планировщики, потом соединения с БД/кэшем.\n- **Лидер‑элекция**: готовьтесь к «морганию» сети/Redis — `LeaderSupervisor` уже делает Start/Stop идемпотентно.\n- **gRPC ответы**: используйте `EnforceMaxSendSize` чуть ниже максимального размера ответов (например, `0.9 * out_grpc_body_size`).\n- **PostgreSQL/CH пулы**: подбирайте `MinConns` ≈ `MaxConns/4`, TTL/idle — исходя из нагрузки и политики сервера.\n- **Планировщик**: критичные задачи — `StopImmediate` (чтобы не тянуть останов), долгие — `StopGraceful` с разумным `Deadline`.\n\n---\n\n## Дорожная карта\n- [ ] Метрики Prometheus: пулы БД, планировщик, лидеры, HTTP/gRPC.\n- [ ] Пробы liveness/readiness HTTP‑эндпоинтами.\n- [ ] Интеграция с OpenTelemetry (tracing/logs).\n- [ ] Тестовые double’ы и пример сервиса (boilerplate).\n\n---\n\n## Лицензия\nСм. файл **LICENSE** в репозитории.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimplegear%2Fkernel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimplegear%2Fkernel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimplegear%2Fkernel/lists"}