Concurrent Data Processing in Elixir: various errata

Hi @Margaret ,

On page VII the book tells us the example and snippets will be all using Elixir version 1.11

But on page 3 almost the end of the page when has a print of the IEx console, the version of the Elixir is 1.9.4 instead of 1.11.


So and the most part of the book suggest use the recompile function on IEx, but sometimes after you change your code you continue to receive :noop on IEx, maybe change the approach to use the r function, e.g., r(Sender), will be more efficient, using this way I tell recompile the Sender module on my application and no matter what if I change my code or not.

2 Likes

On page 26 after start the IEx, the Elixir version is 1.9.4.


On page 31:

iex> {:ok, pid} = GenServer.start(SendServer, [max_retries: 1])
Received arguments: [limit: 1] # instead of limit: 1, it's need to be max_retries: 1

On page 32:

def handle_cast({:send, email}, state) do
  Sender.send_email(email)
  emails = [%{email: email, status: "sent", retries: 0}] ++ state.emails
  # it's missing update the state map and return the new state after update
  {:noreply, state}
end

On page 38, maybe instead of called %Jobber.Job{} struct it could be change for %__MODULE__{}.


On page 38, it is has a private function called random_job_id():

defp random_job_id() do
  :crypto.strong_rand_bytes(5) |> Base.url_encode64(padding: false)
end

So, when called :crypto it’s necessary declare as a extra_applications on mix.exs file, look at on Erlang libraries - The Elixir programming language

Thanks for taking the time to report these issues @herminiotorres! I’ve noted them all down and they’ll be fixed in the next beta version :+1:

1 Like

Hi @svilen ,

On page 64, the Logger.info on init function it was declare like:

Logger.info("Received demand for #{demand} pages")

but when running the app on IEx, the console shows us:

19:28:18.359 [info] PageProducer received demand for 1000 pages

On page 73, when it was suggested to change the tuple for :producer to test buffering events, the loggers on console show messages like:

[warn] GenStage producer PageProducer has discarded 2 events from buffer

But when I try to use the same tuple({:producer, initial_state, buffer_size: :infinity}), I receive this output:

iex(1)> PageProducer.scrap_pages(pages)

20:50:54.066 [info]  Elixir.PageConsumer received ["google.com"]

20:50:54.066 [info]  Elixir.PageConsumer received ["facebook.com"]

20:50:55.068 [info]  Elixir.PageConsumer received ["apple.com"]
 
20:50:57.067 [info]  Elixir.PageConsumer received ["netflix.com"]
 
20:50:58.069 [info]  Elixir.PageConsumer received ["amazon.com"]
 
20:51:01.068 [info]  Elixir.PageProducer received demand for 1 pages
 
20:51:03.070 [info]  Elixir.PageProducer received demand for 1 pages

On page 83 when using the via tuple function.

def via(id) do
  {:via, Registry, {ProducerConsumerRegistry, id}}
end

After start the IEx session, the Logger print this warn:

21:35:00.121 [warn]  :subscribe_to value with type {:via, module(), term()} is deprecated. Change {:via, Registry, {ProducerConsumerRegistry, "online_page_producer_consumer_1"}} to {{:via, Registry, {ProducerConsumerRegistry, "online_page_producer_consumer_1"}}, []} instead.

@herminiotorres Awesome, all this makes sense. Just one thing I’d like to clarify:

I think you may have missed the following sentence, which says:

Now, let’s do a quick experiment. Change buffer_size to 1

Could you please try this and see if the output matches the example in the book?

I’ll try to improve this part, it could be more clear what’s expected :+1:

1 Like

Hi @svilen, I test changing to buffer_size: 1.

And works well.

I like to share my thoughts about the book.

Chapter 1:
I like your thoughts and perspective to use Task and Task.Supervisor, but maybe share how to create our own custom Task.Supervisor.

Chapter 2:
I like the idea you use to create the GenServer and use it to improve the application to run Task on Chapter 1. It has good details about GenServer and the callbacks our module needs to implemented and introduce the last instructions about the tuple and the spec each callback receives as params. I feeling missing how to design the application supervisor tree, and how to think in perspective to guarantee our applications weren’t stop, maybe more content about Registry and how to use how to customize it and Supervisor and DynamicSupervisor too, the difference between both supervisors. The last thing is how to observe and debug, introducing this instrumentation when working with the OTP.

Chapter 3:
I like the idea to drop into GenStage after the GenServer chapter because you are very fresh thoughts and very close to using these concepts for most GenServer applications. In this chapter, the knowledge about the supervisor tree is critical because you need to build how your entire stages need at least one process for each stage running. If some stage of my application it’s going down, the next or previous stage will fail. It could be more content about the Dispatcher, and I feel very quickly and small.

I like the application examples and how to use them to explain and conquer this knowledge about this abstract concept; sometimes it’s difficult to understand, a great book, and congrats. I’m very curious/excited about the next chapters and releases.

2 Likes

Thank you for the kind words, and for sharing your ideas, Herminio! I really appreciate it!

2 Likes

In Adjusting Restart Frequency, it states

By default, max_restarts is set to 3 and max_seconds to 5"

Then it goes ahead asking us to set to 30 seconds. However, the code writes max_seconds: 30_000 seconds which is 500 minutes. It should be max_seconds: 30 instead.

1 Like

Thanks for spotting this Vitor, I’ll make sure this is corrected :+1:

1 Like

Oh, just now noticed the book isn’t finished, or am I wrong?

I’d love to buy this in a physical form in addition to an .epub file. I’ll listen here on this forum for an announcement of the final paper version of the book.

@dimitarvp thanks – we are just in the first beta, so not yet in print. In print date should be August 2021.

2 Likes

I started to reread the new beta version…

On page 15, when has the topic Linking Processes, maybe just “How Process Work”, and you could explain between:
nolink => spawn
link => spawn_link
monitor => spawn_monitor
What do you think?

In Chapter One, on the topic “Supervisor”, maybe you could do a little bit more instrumentation about why occur the IEx process died when it did yet use the Task.Supervisor.

Maybe show the supervise tree use :observer.start(), and follow the process going die when calling the notify_all/1.

After finish the first chapter, I like it more than I read it the first time.

Well done @svilen

1 Like

@svilen @Margaret In Beta 3, page 85, the via function was changed to {{:via, Registry, {ProducerConsumerRegistry, id}}, []}. This does not work. This should only be on the subscribe calls, not the actual name for the child process. The deprecation warning was on the subscription, not in the module useage itself.

Revert this to the original {:via, Registry, {ProducerConsumerRegistry, id}} and then where the subscription happens in page_consumer_supervisor.change2.ex, change the subscription entries to:

subscribe_to: [
        {OnlinePageProducerConsumer.via("online_page_producer_consumer_1"), []},
        {OnlinePageProducerConsumer.via("online_page_producer_consumer_2"), []}
      ]
2 Likes