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
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Архитектура системы
|
|
|
|
|
|
|
|
|
|
Наша система будет состоять из трех компонент.
|
|
|
|
|
* Клиент - процесс запускающий сборку.
|
|
|
|
|
* Воркер - процесс запускающий команды компиляции и тестирования.
|
|
|
|
|
* Координатор - центральный процесс в системе, общается с клиентами и воркерами. Раздаёт задачи
|
|
|
|
|
воркерам.
|
|
|
|
|
|
|
|
|
|
Типичная сборка выглядит так:
|
|
|
|
|
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
|
|
|
|
нужно ознакомиться с существующим кодом.
|
2020-04-09 09:55:04 +00:00
|
|
|
|
- [`distbuild/pkg/tarstream`](./pkg/tarstream) - передача директории через сокет.
|
|
|
|
|
- [`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
|
|
|
|
|
2020-04-05 12:47:58 +00:00
|
|
|
|
После того, как все кубики будут готовы, нужно будет соединить их вместе, реализовав `distbuild/pkg/worker`,
|
2020-04-09 09:55:04 +00:00
|
|
|
|
`distbuild/pkg/client` и `distbuild/pkg/dist`. Код в этих пакетах нужно отлаживать на
|
|
|
|
|
интеграционных тестах в [`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>
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
prime@bee ~/C/shad-go> find distbuild -iname '*.go' | grep -v test | grep -v mock | grep -v pkg/build | xargs wc -l
|
|
|
|
|
23 distbuild/pkg/worker/state.go
|
|
|
|
|
111 distbuild/pkg/worker/worker.go
|
|
|
|
|
45 distbuild/pkg/worker/download.go
|
|
|
|
|
281 distbuild/pkg/worker/job.go
|
|
|
|
|
69 distbuild/pkg/api/heartbeat.go
|
|
|
|
|
121 distbuild/pkg/api/build_client.go
|
|
|
|
|
53 distbuild/pkg/api/build.go
|
|
|
|
|
60 distbuild/pkg/api/heartbeat_handler.go
|
|
|
|
|
142 distbuild/pkg/api/build_handler.go
|
|
|
|
|
56 distbuild/pkg/api/heartbeat_client.go
|
|
|
|
|
288 distbuild/pkg/scheduler/scheduler.go
|
|
|
|
|
119 distbuild/pkg/dist/build.go
|
|
|
|
|
120 distbuild/pkg/dist/coordinator.go
|
|
|
|
|
98 distbuild/pkg/tarstream/stream.go
|
|
|
|
|
42 distbuild/pkg/artifact/client.go
|
|
|
|
|
191 distbuild/pkg/artifact/cache.go
|
|
|
|
|
54 distbuild/pkg/artifact/handler.go
|
|
|
|
|
124 distbuild/pkg/client/build.go
|
|
|
|
|
83 distbuild/pkg/filecache/client.go
|
|
|
|
|
99 distbuild/pkg/filecache/handler.go
|
|
|
|
|
111 distbuild/pkg/filecache/filecache.go
|
|
|
|
|
2290 total
|
|
|
|
|
```
|
|
|
|
|
</details>
|
|
|
|
|
|
2020-04-05 12:47:58 +00:00
|
|
|
|
# Критерии оценки
|
2020-03-08 19:13:14 +00:00
|
|
|
|
|
2020-04-09 09:55:04 +00:00
|
|
|
|
Решение должно проходить все тесты, так же как в обычной задаче.
|
|
|
|
|
|
|
|
|
|
Задача разбита на две части:
|
2021-03-30 22:57:35 +00:00
|
|
|
|
- `distbuild` проверяет решение всех "кубиков". Эта задача рассчитывается как обычная семинарская.
|
2020-04-09 09:55:04 +00:00
|
|
|
|
- `disttest` проверяет интеграционные тесты. Эта задача оценивается как домашка. После успешной попытки, в таблице gdoc
|
|
|
|
|
будет стоять 0. После этого, проверяющие должны будут просмотреть решение и заменить оценку в таблице на 1.
|
2021-03-30 22:59:51 +00:00
|
|
|
|
Это будет значить, что домашнее задание засчитано. Code Review не будет, проверка нужна только чтобы удостовериться, что
|
2020-04-09 09:55:04 +00:00
|
|
|
|
посылка честно проходит все тесты. Отдельный Merge Request создавать не нужно.
|
|
|
|
|
|
|
|
|
|
Чтобы запустить проверку внутри `disttest`, сделайте коммит добавляющий незначащий перенос строки в какой-нибудь файл
|
|
|
|
|
из этой директории.
|