shad-go/distbuild/README.md

130 lines
7.5 KiB
Markdown
Raw Normal View History

2020-03-08 19:13:14 +00:00
# distbuild
В этом задании вам нужно будет реализовать систему распределённой сборки.
Система сборки получает на вход граф сборки и файлы с исходным кодом. Результатом сборки
являются исполняемые файлы и stderr/stdout запущенных процессов.
## Граф сборки
Граф сборки состоит из джобов. Каждый джоб описывает команды, которые нужно запустить на одной машине,
вместе со всеми входными файлами, которые нужны этим командам для работы.
Джобы в графе сборки запускают произвольные команды. Например, вызывать компилятор, линкер или
запускать тесты.
Команды внутри джоба могут читать файлы с файловой системы. Мы будем различать два вида файлов:
- Файлы с исходным кодом с машины пользователя.
- Файлы, которые породили другие джобы.
Команды внутри джоба могут писать результаты своей работы в файлы на диске. Выходные файлы
2020-04-05 12:47:58 +00:00
обязаны находиться внутри его выходной директории. Директория с результатом работы джоба называется
артефактом.
2020-03-08 19:13:14 +00:00
```go
2020-04-05 12:47:58 +00:00
package build
2020-03-08 19:13:14 +00:00
import "crypto/sha1"
// ID задаёт уникальный идентификатор джоба.
//
// Мы будем использовать sha1 хеш, поэтому ID будет занимать 20 байт.
type ID [sha1.Size]byte
// Job описывает одну вершину графа сборки.
type Job struct {
2020-04-05 12:47:58 +00:00
// ID задаёт уникальный идентификатор джоба.
//
// ID вычисляется как хеш от всех входных файлов, команд запуска и хешей зависимых джобов.
//
2020-04-05 15:19:59 +00:00
// Выход джоба целиком определяется его ID. Это важное свойство позволяет кешировать
2020-04-05 12:47:58 +00:00
// результаты сборки.
ID ID
// Name задаёт человекочитаемое имя джоба.
//
// Например:
// build gitlab.com/slon/disbuild/pkg/b
// vet gitlab.com/slon/disbuild/pkg/a
// test gitlab.com/slon/disbuild/pkg/test
Name string
// Inputs задаёт список файлов из директории с исходным кодом,
// которые нужны для работы этого джоба.
//
// В типичном случае, тут будут перечислены все .go файлы одного пакета.
Inputs []string
// Deps задаёт список джобов, выходы которых нужны для работы этого джоба.
Deps []ID
// Cmds описывает список команд, которые нужно выполнить в рамках этого джоба.
Cmds []Cmd
2020-03-08 19:13:14 +00:00
}
```
## Архитектура системы
Наша система будет состоять из трех компонент.
2022-03-06 00:10:55 +00:00
* Клиент - процесс, запускающий сборку.
* Воркер - процесс, запускающий команды компиляции и тестирования.
2020-03-08 19:13:14 +00:00
* Координатор - центральный процесс в системе, общается с клиентами и воркерами. Раздаёт задачи
воркерам.
Типичная сборка выглядит так:
1. Клиент подключается к координатору, посылает ему граф сборки и входные файлы для графа сборки.
2021-03-30 22:55:43 +00:00
2. Координатор сохраняет граф сборки в памяти и начинает его исполнение.
2020-03-08 19:13:14 +00:00
3. Воркеры начинают выполнять вершины графа, пересылая друг другу выходные директории джобов.
4. Результаты работы джобов скачиваются на клиента.
2020-04-05 12:47:58 +00:00
# Как решать эту задачу
2020-03-10 12:08:59 +00:00
2020-04-05 12:47:58 +00:00
Задача разбита на шаги. В начале, вам нужно будет реализовать небольшой набор независимых пакетов,
которые реализует нужные примитивы. Код в этих пакетах покрыт юниттестами. В каждом пакете находится
файл README.md, объясняющий подзадачу.
2020-03-10 12:08:59 +00:00
2020-04-05 12:47:58 +00:00
Рекомендуемый порядок выполнения:
2020-03-08 19:13:14 +00:00
2020-04-09 09:55:04 +00:00
- [`distbuild/pkg/build`](./pkg/build) - определение графа сборки. В этом пакете ничего писать не нужно,
2020-04-05 12:47:58 +00:00
нужно ознакомиться с существующим кодом.
- [`distbuild/pkg/tarstream`](./pkg/tarstream) - передача директории через сокет. В этом пакете ничего
писать не нужно, нужно ознакомиться с существующим кодом.
2020-04-09 09:55:04 +00:00
- [`distbuild/pkg/api`](./pkg/api) - протокол общения между компонентами.
- [`distbuild/pkg/artifact`](./pkg/artifact) - кеш артефактов и протокол передачи артефактов между воркерами.
- [`distbuild/pkg/filecache`](./pkg/filecache) - кеш файлов и протокол передачи файлов между компонентами.
- [`distbuild/pkg/scheduler`](./pkg/scheduler) - планировщик с эвристикой локальности.
2020-03-08 19:13:14 +00:00
2022-05-08 15:35:40 +00:00
После того, как все кубики будут готовы, нужно будет соединить их вместе, реализовав [`distbuild/pkg/worker`](./pkg/worker),
[`distbuild/pkg/client`](./pkg/client) и [`distbuild/pkg/dist`](./pkg/dist). Код в этих пакетах нужно отлаживать на
2023-04-26 12:29:27 +00:00
интеграционных тестах в [`distbuild/disttest`](./disttest).
2020-03-08 19:13:14 +00:00
2020-04-05 12:47:58 +00:00
Код тестов в этом задании менять нельзя. Это значит, что вы не можете менять интерфейсы в тех местах, где
код покрыт тестами.
2020-03-08 19:13:14 +00:00
2020-04-05 12:54:05 +00:00
<details>
<summary markdown="span">Сколько кода нужно написать?</summary>
```
2023-04-26 12:29:27 +00:00
prime@fedora ~/C/s/distbuild (master)> find -iname '*_solution.go' | grep -v scheduler_solution| xargs wc -l
123 ./pkg/api/build_client_solution.go
140 ./pkg/api/build_handler_solution.go
58 ./pkg/api/heartbeat_client_solution.go
62 ./pkg/api/heartbeat_handler_solution.go
5 ./pkg/artifact/cache_solution.go
44 ./pkg/artifact/client_solution.go
56 ./pkg/artifact/handler_solution.go
126 ./pkg/client/build_solution.go
121 ./pkg/dist/build_solution.go
122 ./pkg/dist/coordinator_solution.go
85 ./pkg/filecache/client_solution.go
5 ./pkg/filecache/filecache_solution.go
101 ./pkg/filecache/handler_solution.go
5 ./pkg/tarstream/stream_solution.go
47 ./pkg/worker/download_solution.go
283 ./pkg/worker/job_solution.go
25 ./pkg/worker/state_solution.go
113 ./pkg/worker/worker_solution.go
1521 total
2020-04-05 12:54:05 +00:00
```
</details>