Today I Learned

8 posts about #elixir

Revealing struct information

In Elixir when we are printing struct we can hide struct’s details implementing Inspect protocol. For example the DateTime struct is doing that so when we are inspecting it it shows us pretty version instead of the detailed one.

iex(1)> now = DateTime.utc_now()
~U[2020-10-06 10:59:58.388743Z]
iex(2)> IO.inspect(now)
~U[2020-10-06 10:59:58.388743Z]

If we want to reveal all the information that the struct contains we can use structs: false option.

iex(5)> IO.inspect(now, structs: false)
  __struct__: DateTime,
  calendar: Calendar.ISO,
  day: 6,
  hour: 10,
  microsecond: {388743, 6},
  minute: 59,
  month: 10,
  second: 58,
  std_offset: 0,
  time_zone: "Etc/UTC",
  utc_offset: 0,
  year: 2020,
  zone_abbr: "UTC"

Long polling in BroadwaySQS

By default BroadwaySQS doesn’t wait for a message to arrive if no messages are available in the queue. Also, it has a default 5 seconds duration for which the producer waits before making a request for more messages. This may result in few second’s gap between enqueuing a message and processing it. For many cases this is good enough, but sometimes one may need a message to be processed immediately after enqueueing. In such cases you should consider using long polling.

To achieve it in BroadwaySQS just set wait_time_seconds to e.g. 10 seconds (or any value from 1 to 20) and receive_interval to 0 in producer’s options.


def start_link(_opts) do
  producer = Application.get_env(:scanner, :broadway_producer, BroadwaySQS.Producer)
  queue_url = Application.get_env(:ex_aws_sqs, :queue_url)

    name: __MODULE__,
    producers: [
      default: [
        module: {
          queue_url: queue_url, wait_time_seconds: 20, receive_interval: 0
        stages: 1
    processors: [
      default: [stages: 50]

Mocking behaviour in child processes

Imagine you have a process which is responsible for consuming some sort of queue and spawning a separate process for each given job.

Each of the job processors later called workers communicates with some infrastructure layers for eg. external API, database, etc. We are injecting infrastructure to workers via configuration:

defp current_impl do
  Application.get_env(:scanner, :ensure_file, __MODULE__.AwsImpl)

Each injected implementation must implement complementary behaviour for eg.

defmodule Scanner.Scans.EnsureFile.Impl do
  @callback call(String.t, String.t) :: {:ok, any()} | {:error, any()}

In this setup, we could mock the whole behaviour using Mox :

# test_suport.ex or other file with your test configuration
Mox.defmock(Scanner.EnsureFileMock, for: Scanner.Scans.EnsureFile.Impl)

# actual test
expect(Scanner.EnsureFileMock, :call, fn ^bucket, ^path -> 
  {:ok, :response} 

When we run this test with the given context we would gen an error:

(Mox.UnexpectedCallError) no expectation defined for

The reason is that Mox by default works in private mode which is applying our mocked behaviour only for the current process - in our scenario our tested module spawns workers which are the real consumers of our mock and the implementation is only mocked for our test process. To allow our child process to consume the mock we need to set Mox in our test the global mode:

setup :set_mox_global

Or we could use:

setup :set_mox_from_context

Which will set the private mode only when a test has async: true otherwise it would use global mode.