D4no0

D4no0

I am currently digging in some CI scripts using github actions. They seem to be installing elixir/erlang using asdf and cache them afterwards. It seems they work pretty well currently, however this makes me question whether it is smart to compile OTP from source in a CI environment instead of using a pre-built image?

There are few clear benefits to the asdf approach:

  1. You can use .tools-versions to keep the versions for both dev and CI envs;
  2. You don’t have to rely on pre-built images availability, this can be both for older versions of OTP or bleeding edge ones.

My main concerns when I saw usage of asdf is: how controllable the env where OTP is compiled is? I can see how this can easily backfire when you want to use a older OTP version that doesn’t support openssl 3+.

I’ve took a look at some OSS projects like phoenix and it seems they are using erlef/setup-beam@v1 usually:

- name: Set up Elixir
  uses: erlef/setup-beam@v1
  with:
    elixir-version: ${{ matrix.elixir }}
    otp-version: ${{ matrix.otp }}

Any thoughts on this? My aim is to find the version of config that is the easiest to use and configure.

Showing Posts 1 to 10

stefanluptak

stefanluptak

We’re using it like this and this step takes only 6s. What it does is just some unzipping etc., so no compilation involved.

- uses: erlef/setup-beam@v1
  id: setup-beam
  with:
    version-file: .tool-versions
    version-type: strict
D4no0

D4no0 OP

Damn, I was thinking about writing a bash script to achieve the same, I guess I should have started by reading the action documentation :smiley: . This is great, thanks a lot!

BTW, on this topic of using .tools-versions, are you using .tools-versions to set the docker image version for building a release too? (assuming you are using docker containers for deploys).

stefanluptak

stefanluptak

No, I don’t, but it would be nice. Please post here if you find an elegant approach. I haven’t researched it yet.

BartOtten

BartOtten

You can also use a version matrix to test the project with multiple erlang/elixir combinations; although it causes some issues with ‘mix format —check-formatted’ as different versions use different formatting. Still need to fix it by making that check depending on the version.

Also: instead of asdf check mise; switched last year and never looked back.

https://github.com/BartOtten/routex/blob/main/.github/workflows/elixir.yml

D4no0

D4no0 OP

I’ve always wondered, does this kind of caching strategy make any sense?

From your example:

    - name: Cache deps
      id: cache-deps
      uses: actions/cache@v3
      env:
        cache-name: cache-elixir-deps
      with:
        path: deps
        key: ${{ runner.os }}-mix-${{ env.cache-name }}-${{ hashFiles('**/mix.lock') }}
        restore-keys: |
          ${{ runner.os }}-mix-${{ env.cache-name }}-

    - name: Cache compiled build
      id: cache-build
      uses: actions/cache@v3
      env:
        cache-name: cache-compiled-build
      with:
        path: _build
        key: ${{ runner.os }}-mix-${{ env.cache-name }}-${{ hashFiles('**/mix.lock') }}
        restore-keys: |
          ${{ runner.os }}-mix-${{ env.cache-name }}-
          ${{ runner.os }}-mix-

Does pretty much the same thing, after compiling deps and source-code for a mix.lock, you will always have collision when trying to cache build, meaning that you will always have to re-compile the new application code until mix.lock changes, or I am missing something?

BartOtten

BartOtten

To be honest: it’s on my todo list to see if it works. Wrote it years ago and as having the best CI was not my main goal, I went along once it did run reliably.

Feel free to copy the script and check / improve (and let me know)

BartOtten

BartOtten

@D4no0 have look at https://github.com/BartOtten/routex/actions/runs/11672515348/job/32501296547

Seems to work as intended (on mobile so did not look deep into it)

D4no0

D4no0 OP

You can notice that the new cache is not saved as that key already exists. I am coming from the gitlab world, where we can update/delete cache, so I am always about caching the latest version, I don’t really dig this immutable cache ideology.

Looking at the official documentation for cache action I found how I can achieve that:

A cache today is immutable and cannot be updated. But some use cases require the cache to be saved even though there was a “hit” during restore. To do so, use a key which is unique for every run and use restore-keys to restore the nearest cache. For example:

  • name: update cache on every commit uses: actions/cache@v3 with: path: prime-numbers key: primes-${{ runner.os }}-${{ github.run_id }} # Can use time based key as well restore-keys: | primes-${{ runner.os }}

Please note that this will create a new cache on every run and hence will consume the cache quota.

This key will ensure that you will be able to generate new cache for each new run of the workflows. I am using it the following way currently:

- name: Build Cache
  uses: actions/cache@v4
  with:
    key: ${{ runner.os }}-build-${{ hashFiles('./mix.lock') }}-${{ github.run_id }}
    restore-keys: |
      ${{ runner.os }}-build-${{ hashFiles('./mix.lock') }}
    path: |
      ./_build 

For my current use-case the only thing I care about is that pipelines run as fast as possible, the amount of storage used by cache is irrelevant, not to mention that you really have to cache a lot to hit the 10GB quota for free projects. We are also running this stuff on self-hosted runners for this project, so you can say the amount of space for caching is unlimited :smiley: .

I use the same strategy to cache the PLT for dialyzer and the pipeline is able to run in 20s, well the project is empty yet but I think it can be kept under 1 min easily.

akash-akya

akash-akya

erlef/setup-beam works well for windows & Linux but sadly it does not support macos. I used to use asdf for macos but it was too slow. It used to take around 30m to install Erlang & Elixir.

Few months back I switched to Nix based pipeline and it now takes <1m. Nix has its own caching mechanism which works pretty well.

  macos:
    runs-on: macos-11
    steps:
      - uses: actions/checkout@v4
      - uses: DeterminateSystems/nix-installer-action@main
      - uses: DeterminateSystems/magic-nix-cache-action@main
      - uses: DeterminateSystems/flake-checker-action@main
      - run: nix develop --command mix deps.get
      - run: nix develop --command mix test --trace

I think there is some nix package to read config from .tool-versions as well.

D4no0

D4no0 OP

I have a sample config using asdf I was provided. The initial compilation is pretty slow here too, but the idea is to heavily rely on cache. If you do that, you only have to wait for long when you are switching between erlang versions, which is not a thing you do often for applications, for libraries where you want to ensure compatibility between different versions I agree this is still a problem.

This might be worth investigating, as I hate this immutable cache action that is provided by default by github, really makes something that should have been easy into an ordeal.

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 92995 915
New
caslu
I want to open this thread for you all to discuss and help those who really like Ash but are still hesitant to use it in a real project. ...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
Herve37
We’re evaluating API mocking tools for OpenAPI-based projects and would love to hear what other teams are using. We’re particularly inte...
New
GES233
I’m posting this in response to Jose’s recent tweet (Cr. link) : People are sleeping on Elixir for a coding harness: Hot-code swappi...
New
_mfierro
Hello, I wrote Stop My Hand, a Scattergories-like web application using Phoenix/LiveView as my learning project for Elixir (after readin...
New
nseaSeb
AcmeScript — Writing JS hooks as if I were still using Elixir I’ve been having fun building a little something over the last few days: Ac...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews