Runtimes and Environments
Every code cell in Nextjournal has a runtime assigned to it that handles the execution of a code cell’s contents within a computational environment (file system, libraries, packages, etc):
To give a more technical explanation: a Nextjournal environment is a Docker image that’s providing a file system to the runtime. It includes an operating system, system libraries and language-specific libraries.
A runtime is a process that runs inside a Docker container that’s making use of its associated Docker image. Runtimes also implement a communication protocol to execute code in Nextjournal’s code runner.
Let’s take a more detailed look at runtimes:
When you add a new code cell, Nextjournal will automatically add a default runtime for that language’s programming language. Multiple cells of the same language will share a runtime and subsequently that runtime’s environment’s file system (unless you change this). You can find all runtimes that are used in your notebook in the sidebar’s Runtimes section or in the Runtimes section at the bottom of your notebook:
Each runtime also shows the environment it’s using right next to it. Clicking the environment brings you to the notebook that exports it. How environments exactly work are explained in detail further down in this notebook, under Environments.
You will also see that every code cell shows its corresponding environment in its bottom right corner (right next to the language it’s using).
When executing a cell, a runtime goes through various states. The details of what’s happening are logged to the runner log which you can find in the top bar of the Nextjournal editor:
If the runtime was just added and no code has been executed yet, you’ll find that the runtime shows a gray dot, meaning that it’s stopped. That means once you execute a cell that uses this runtime, the runtime will go through a booting phase (shown by a yellow dot). Because of this booting phase, the first run will take a bit longer than subsequent runs. Once the runtime is running (shown by a green dot), execution should be reasonably fast, depending on what you are trying to accomplish. A red dot and an error message will indicate that there was an error during execution or booting of the runtime.
There are some more states a runtime can show, like Preparing Download, Downloading, Restoring or Uploading but those are mainly indicating the housekeeping around the underlying environment’s Docker image.
Mind that a runtime will automatically shut down after 20 minutes of idle time.
Some use cases, like training a neural net, can potentially take hours to run. At the moment, Nextjournal does not enforce limitations other than shutdown after 20 minutes of idle time. This means, your cell keeps running even when you close the browser window. Just make sure that you are writing your results to
/results so that they are persisted and versioned.
Clicking the gear button next to a runtime in the sidebar shows all settings a runtime has available to it.
Let’s run through them:
Name: A name can be useful when you export your runtime’s environment so that it can be used in other articles without having to install all packages over again. Example: A name for an environment that is configured for GPU usage and has some Machine Learning packages installed could be "Python ML/GPU".
Type: This defines how a runtime is executing code. By default, this will use the Nextjournal type (our own runtime protocol). When you import a Jupyter notebook however, this will use the Jupyter type so that code is executed using e.g. the Jupyter IPython kernel.
Environment: This is a Docker image that provides a file system to be used by the runtime. You can change this to an environment that has been exported by another notebook to make use of that notebook’s installed packages. You can learn about this in detail in this notebook’s Environments section.
Environment Variables & Secrets: You can make new environment variables available to your runtime or override existing ones. Click show inherited to show all existing variables that were provided by the base environment. You can also use secrets as value for an env variable. This is explained in detail in the Using secrets guide.
Mounts: You can make the contents of e.g. a GitHub repository or a S3 bucket available to your runtime by adding it to mounts. You can define under what directory a mounted resource will be available in the file system.
Machine Type: This defines the compute resources available to your runtime. For example, you might want to add GPUs to perform certain Machine Learning tasks. See Configuring GPUs and Memory for more details.
Export the environment: This makes your runtime’s environment’s underlying Docker image available for reuse. Once you check Export, Nextjournal will upload the environment’s Docker image to a registry so that it can be reused in the same or other notebooks, or on any other computer.
Configuring GPUs and Memory
GPUs are configured in a runtime's settings under Machine Type. Click the gear button next to the runtime name in the sidebar to reveal this menu. If no runtime exists, first add a new code cell in your preferred language.
Once in the runtime settings:
Select the CPU/RAM configuration
Select the GPU
Not all compute resources are enabled by default. Please contact us using intercom or e-mail to make them available.
The runner must already be inactive or must be shutdown for these changes to take effect.
The runner will mount the CUDA and cuDNN libraries automatically. Which version is mounted is controlled by the
NEXTJOURNAL_MOUNT_CUDA environment variable, and will default to the latest version we currently have installed. The current valid values are:
See Runtime Settings for documentation on all runner settings.
By default, a runtime’s file system state is transient, meaning changes to the file system will not be persisted once the runtime is reset or shuts down (like after 20 minutes of idle time). When a runtime has been reset, all cells that install packages will have to be re-run to make them available again.
To get around this, and to allow for easy sharing of your runtime environment with other notebooks, Nextjournal provides a runtime setting to save a runtime’s environment. Behind the scenes, this creates a new snapshot of your runtime’s environment’s current file system state and uploads it to Nextjournal’s registry. Once it has been uploaded and the notebook is published, other notebooks can import your saved environment. By doing so, they will get an exact copy of your environment without having to re-install anything.
Saving an environment has the additional benefit of being immediately notified of all changes to it since you last saved it. This is especially helpful when you try out upgrading drivers or packages. If you find out that your upgrade broke something you can simply omit saving the changes to your environment. Resetting the runtime will revert it back to the last saved environment’s state.
Let’s take a look at an example. In the following video, you will see how we install a package and save its environment. Following that, we will upgrade the package and you will see how Nextjournal will notify you that the file system state has been changed compared to your environment’s last saved state.
Any saved environment can be imported by another notebook once the notebook that saved the environment has been published. This allows you to use all packages provided by that environment without having to install or configure anything. Imported environments always refer to a specific snapshot of the saved environment (the version at the time you imported it). Any changes you make to this environment will be local to you and won’t have any effect on the originally saved environment.
Here is an example of how to import a saved environment from another notebook:
Extending computational capabilities
Saving and importing of environments make it fairly easy to extend someone else’s environment for your own needs. Simply import a saved environment, install any additional packages you need for your use case and save it again so other notebooks can make use of it.
In fact, Nextjournal makes heavy use of this feature for all the programming languages it provides. Let’s take Nextjournal’s default Python runtime for example. If you add a Python code cell and open its corresponding runtime’s settings, you’ll find that it uses a Python 3 environment. If you click the little arrow next to it, it will open the notebook that saved the Python 3 environment. The notebook will show you everything that is installed in the environment. Furthermore, you will also see that the Python 3 environment also extends upon yet another environment — the Bash environment which is provided by another notebook. Finally, the Bash environment is based on a Ubuntu Base Docker image that lives in the same notebook.