github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/README.md (about) 1 # Tilt Architecture 2 3 A short guide to the internal code architecture of Tilt. 4 5 ## Overview 6 7 Tilt is fundamentally a control loop with 4 pieces: 8 9 - A central `EngineState` that represents everything Tilt "knows". 10 - A `Store` that mediates changes to `EngineState` 11 - Subscribers that read from the state store to do stuff. 12 - Actions that modify the state store. 13 14 ### The Control Loop 15 16 After a state change, the state store calls `OnChange` on each subscriber. Each 17 subscriber diffs the state to see what changed since the subscriber last looked 18 at the state. 19 20 Depending on what changed, the subscriber may kick off some work, or start 21 watching an external system (like a Kubernetes Pod) for changes. As the 22 subscriber does work, the subscriber creates actions and calls 23 `store.Dispatch(action)`. 24 25 These actions represent state changes. The state store applies these actions to 26 the state. When it's done applying actions, it calls `OnChange` again, and the 27 process starts over. 28 29 ### Examples 30 31 Almost everything in Tilt is implemented as a subscriber that fires actions. 32 33 - **The pod log manager.** On each `OnChange`, the pod log manager looks for 34 new pods that Tilt knows about. If a new pod appears, the log manager 35 starts streaming it's logs. As new logs come in, it dispatches actions 36 to send the logs to the engine state. 37 38 - **The Tilt browser UI.** When your browser visits `localhost:10350`, 39 Tilt creates a new subscriber that's tied to a WebSocket connection. 40 On each `OnChange`, Tilt pushes status updates to the browser 41 on the WebSocket. 42 43 - **The file watcher.** On each `OnChange`, the file watcher looks at all the file 44 paths in the state store that we expect to trigger updates. It diffs these 45 against all the file watches it's currently managing, then creates new watches 46 and deletes unneeded watches. Each watch uses OS APIs to watch the file system, 47 then converts those file system notifications into actions to dispatch. 48 49 ### Concurrency 50 51 A subscriber's `OnChange` method is synchronized. The state store will not call 52 `OnChange` again until the previous `OnChange` has finished. 53 54 When a subscriber calls `Dispatch(action)`, that action is put into a FIFO 55 queue, and the call returns immediately. 56 57 The state store typically processes actions in a batch after a backoff period, 58 updating the state to reflect what's in the actions. 59 60 As a corollary, subscribers should not expect an OnChange() call for every 61 action. For example, if a pod is created then deleted quickly, the actions that 62 notify the state store of the create and delete might get grouped together, and 63 the subscribers will never see the pod! 64 65 ## Package structure 66 67 ### Core Packages 68 69 Here are the core Tilt packages that manage the control loop: 70 71 - [store](store) - The central `EngineState`, `Store`, `Subscriber`, and `Action` components 72 73 - [engine](engine) - Functions that translate actions into state changes, and registration logic 74 for subscribers. 75 76 - [model](../../pkg/model) - Data models that are shared by the `store` package and other client libraries. 77 78 ### Subscriber Packages 79 80 Most subscribers are subpackages of `engine`. Here's a partial listing of important ones: 81 82 - [engine/buildcontrol](engine/buildcontrol) - Decides when to build images and 83 deploy resources 84 85 - [engine/configs](engine/configs) - Decides when to re-execute the Tiltfile 86 87 - [engine/fswatch](engine/fswatch) - Sets up file system watches, and dispatches 88 actions when files have changed 89 90 - [engine/k8swatch](engine/k8swatch) - Watches Kubernetes resources, and 91 dispatches actions when objects (like pods and events) are created, updated, 92 or deleted. 93 94 - [engine/local](engine/local) - Manages servers run by `local_resource(serve_cmd)` 95 96 - [engine/portforward](engine/portforward) - Sets up port-forwarding to Kubernetes pods. 97 98 - [engine/runtimelog](engine/runtimelog) - Streams logs from Kubernetes and 99 Docker Compose containers. 100 101 There are a few major subscribers that aren't subpackages of `engine`. 102 103 - [hud](hud) - The termbox user interface 104 105 - [hud/server](hud/server) - Creates websocket connections to send updates to the browser. 106 107 ### Client packages 108 109 Almost all other packages in Tilt are client libraries that abstract over 110 external services that subscribers need to interact with. Here's a partial listing: 111 112 - [docker](docker) - An abstraction over the Docker client library. 113 114 - [build](build) - An abstraction over docker build, with helpers for building 115 docker context tarballs. 116 117 - [tiltfile](tiltfile) - Executes Tiltfiles, and implements all Tiltfile functions. 118 119 - [k8s](k8s) - An abstraction over Kubernetes' client-go. 120 121 - [watch](watch) - An abstraction over OS file APIs (like FSEvents and inotify). 122 123 - [rty](rty) - A termbox rendering library. 124 125 ### User interfaces 126 127 - [cmd/tilt](../cmd/tilt) - The "main" entrypoint for the CLI. 128 129 - [cli](cli) - All Tilt CLI commands. 130 131 - [web/src](../web/src) - The Tilt web interface. 132