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