link asymmetry in process ring - process

I'm currently working through the ubiquitous process ring in elixir.
The ring is linked, but in the following fashion:
iex(1)> Ring.Worker.create_ring_of_linked_processes(3)
Ring.Worker.create_ring_of_linked_processes(3)
[%{"links" => [#PID<0.121.0>, #PID<0.120.0>], "pid" => #PID<0.122.0>},
%{"links" => [#PID<0.120.0>, #PID<0.122.0>], "pid" => #PID<0.121.0>},
%{"links" => [#PID<0.121.0>], "pid" => #PID<0.120.0>}]
I've noticed an asymmetry in the links here - should #PID<0.120.0> have the mapping "links" => [#PID<0.121.0>,#PID<0.122.0>] rather than just "links" => [#PID<0.121.0>] ?
The code is as follows:
def loop() do
receive do
{:link, pid} when is_pid(pid) ->
Process.link(pid)
loop()
end
end
def create_ring_of_linked_processes(num_of_processes) do
num_of_processes
|> create_processes
|> link_processes([])
end
def link_processes([pid1, pid2 | rest], linked_processes) do
send(pid1, {:link, pid2})
:timer.sleep(1)
{:links, links} = Process.info(pid1, :links)
link_processes(
[pid2 | rest], [%{"pid" => pid1, "links" => links} | linked_processes]
)
end
def link_processes([pid | []], linked_processes) do
%{"pid" => first_pid, "links" => _} = List.last(linked_processes)
send(pid, {:link, first_pid})
:timer.sleep(1)
{:links, links} = Process.info(pid, :links)
[%{"pid" => pid, "links" => links} | linked_processes]
end
#spec create_processes(integer) :: [pid]
def create_processes(num_of_processes) do
for _ <- 1..num_of_processes, do: spawn(__MODULE__, :loop, [])
end

This is because you're linking the processes at the same time as collecting its :links, but some links for that process are being created after you collect its links.
For example, if you spawn a process a, and then collect its links, it'll be an empty list.
iex(1)> a = spawn(fn -> :timer.sleep(:infinity) end)
#PID<0.82.0>
iex(2)> Process.info(a, :links)
{:links, []}
If you spawn b now and link it to a, b will have [a] in its links and a will have [b].
iex(3)> b = spawn(fn -> Process.link(a); :timer.sleep(:infinity) end)
#PID<0.85.0>
iex(4)> Process.info(b, :links)
{:links, [#PID<0.82.0>]}
iex(5)> Process.info(a, :links)
{:links, [#PID<0.85.0>]}
So, you need to collect the links for each process after all the linking is complete if you want the final links for each process.

Related

Conn being redirect only on test with status 307

I'm writing some controllers tests, however, every controller test, even without authentication, fails because the conn is redirect to somewhere else.
The strange is that in my code I never redirect or return such status (307), only CRUD: 200,201, 400 and 500, without redirecting.
Here is one of my controller test:
defmodule SysbovApiWeb.Animals.AnimalsControllerTest do
use SysbovApiWeb.ConnCase, async: true
import SysbovApi.Factory
import SysbovApi.UserAuth
setup %{conn: conn} do
%{id: farm_id} = insert(:farm)
conn = authenticate(conn)
%{conn: conn, farm_id: farm_id}
end
describe "create/2" do
test "returns 201 when all params are correct", %{conn: conn, farm_id: farm_id} do
conn =
post(conn, "/api/v1/farms/animals", %{
"name" => "Macabeuzinho",
"father" => "Macabeus",
"mother" => "Macabeia",
"breed" => "raro",
"color" => "brown",
"weight" => Decimal.new("10.10"),
"farm_id" => farm_id
})
assert %{
"animal" => %{
"breed" => _,
"color" => _,
"farm_id" => _,
"father" => _,
"id" => _,
"mother" => _,
"name" => _,
"weight" => _
}
} = json_response(conn, 201)
end
end
describe "index/2" do
test "returns all animals given a farm", %{conn: conn, farm_id: farm_id} do
insert_list(2, :animal, farm_id: farm_id)
conn = get(conn, "/api/v1/farms/#{farm_id}/animals")
%{animals: animals} = json_response(conn, 200)
assert is_list(animals)
assert length(animals) == 2
end
end
describe "show/2" do
test "returns a specific animal given a farm", %{conn: conn, farm_id: farm_id} do
animal = insert(:animal, farm_id: farm_id)
conn = get(conn, "/api/v1/farms/#{farm_id}/animals/#{animal.id}")
assert %{
"animal" => %{
"breed" => _,
"color" => _,
"farm_id" => _,
"father" => _,
"id" => _,
"mother" => _,
"name" => _,
"weight" => _
}
} = json_response(conn, 200)
end
end
describe "delete/2" do
test "correctly deletes an animal given a id", %{conn: conn, farm_id: farm_id} do
animal = insert(:animal, farm_id: farm_id)
conn = delete(conn, "/api/v1/farms/animals/#{animal.id}")
assert %{deleted: true} = json_response(conn, 200)
end
end
end
My controller:
defmodule SysbovApiWeb.Animals.AnimalsController do
use SysbovApiWeb, :controller
alias SysbovApi.CreateAnimals
alias SysbovApi.Farm.AnimalsRepo
alias SysbovApi.Animals.AnimalsRepo
def create(conn, params) do
case CreateAnimals.run(params) do
{:ok, animal} ->
conn
|> put_status(201)
|> render("create.json", %{animal: animal})
{:error, changeset} ->
conn
|> put_status(400)
|> render(SysbovApiWeb.ErrorView, "400.json", %{changeset: changeset})
end
end
def index(conn, %{"farm_id" => farm_id}) do
case AnimalsRepo.get_animals(farm_id) do
{:ok, animals} ->
render(conn, "index.json", %{animals: animals})
_ ->
conn
|> put_status(400)
|> render(SysbovApiWeb.ErrorView, "400.json")
end
end
def show(conn, %{"animal_id" => animal_id}) do
case AnimalsRepo.get_animal(animal_id) do
{:ok, animal} ->
render(conn, "show.json", %{animal: animal})
{:error, error} ->
conn
|> put_status(500)
|> render("500.json", %{error: error})
end
end
def delete(conn, %{"animal_id" => animal_id}) do
case AnimalsRepo.delete_animal(animal_id) do
{:ok, _deleted} ->
render(conn, "delete.json", %{deleted: true})
{:error, error} ->
conn
|> put_status(500)
|> render(SysbovApiWeb.ErrorView, "500.json", %{error: error})
end
end
end
and my conn case:
defmodule SysbovApiWeb.ConnCase do
#moduledoc """
This module defines the test case to be used by
tests that require setting up a connection.
Such tests rely on `Phoenix.ConnTest` and also
import other functionality to make it easier
to build common data structures and query the data layer.
Finally, if the test case interacts with the database,
we enable the SQL sandbox, so changes done to the database
are reverted at the end of every test. If you are using
PostgreSQL, you can even run database tests asynchronously
by setting `use SysbovApiWeb.ConnCase, async: true`, although
this option is not recommended for other databases.
"""
alias Ecto.Adapters.SQL.Sandbox
use ExUnit.CaseTemplate
using do
quote do
# Import conveniences for testing with connections
import Plug.Conn
import Phoenix.ConnTest
import SysbovApiWeb.ConnCase
alias SysbovApiWeb.Router.Helpers, as: Routes
# The default endpoint for testing
#endpoint SysbovApiWeb.Endpoint
end
end
setup tags do
:ok = Sandbox.checkout(SysbovApi.Repo)
unless tags[:async] do
Sandbox.mode(SysbovApi.Repo, {:shared, self()})
end
{:ok, conn: Phoenix.ConnTest.build_conn()}
end
end
the really strange part is that the conn is only redirected when running all tests, if I test each route, manually, all works fine.
What I'm doing wrong?

Linear grammar, derive a word

Assuming a right-linear grammar is given how would you show the steps to derive a word? For example if I had the grammer:
S -> aA
A -> bA
A -> aB
B -> cB
B -> a
And I wanted to constuct the word abbbacca. How would I show my step derivertation? Would it be:
S => A => A => A => A => B => B => B
or somethiong more akin to:
aA => abA => abbA => abbbA => abbbaB => abbbacB => abbbaccB => abbbacca
Converting comments to an answer so the question can disappear from the unanswered lists ...
The form
S => aA => abA => abbA => abbbA => abbbaB => abbbacB => abbbaccB => abbbacca
is the more usual, and preferable, way to show the derivation. For extra credit, especially so with larger grammars, it may also be useful to show the label of the rule applied on the derivation arrow, something like
S =(1)=> aA
Of course, for this to be really useful the rules have to have labels !

mocking a function call in midje

Say I have a function
(defn extenal_api_fn [stuff]
... do things....
)
(defn register_user [stuff]
(external_api_fn stuff))
And then a test
(def stuff1
{:user_id 123 })
(def stuff2
{:user_id 234})
(background (external_api_fn stuff1) => true
(with-redefs [external_api_fn (fn [data] (println "mocked function"))]
(register_user stuff1) => true)
(register_user stuff2) => true)
(facts "stuff goes here"
(fact "user that registers correctly
(= 1 1) => truthy)
(fact "user that has a registration failure"
(= 1 2) => falsy))
This fails with
"you never said #'external_api_fn" would be called with these arguments:
contents of stuff1
What would be a good way to stub this function call (in only some cases) in order to simulate an internal transaction failure.
You could use Midje's provided:
(fact
(register_user stuff1) => :registered
(provided
(extenal_api_fn stuff1) => :registered))
(fact
(register_user stuff2) => :error
(provided
(external_api_fn stuff2) => :error))
You can also stub a function to return a value no matter input parameters by using anything in place of the function argument:
(fact
(register_user stuff2) => :error
(provided
(external_api_fn anything) => :error))

Fluent Nhibernate QueryOver and Joins

I'm in the process of learning Fluent nHibernate. I'm having trouble with building a query thats not quite the same as the classic examples I've found online. Typically I've found this example:
IQueryOver<Cat,Cat> catQuery =
session.QueryOver<Cat>(() => catAlias)
.JoinAlias(() => catAlias.Kittens, () => kittenAlias)
.Where(() => catAlias.Age > 5)
.And(() => kittenAlias.Name == "Tiddles");
So from what I understand in this example a Cat object is being returned after being joined on Kittens and then filtered using the kittens name and the cat's age. And the join works because the Cat object has a property called Kittens.
An example of what I'm trying to do would look like this:
Forest f = null;
Tree t = null;
ForestsFound = session.QueryOver<Forest>(() => f)
.JoinAlias(() => t.Forest, () => f)
.Where(() => t.NumberOfTrees > 1000)
.List<Forest>()
.ToList<Forest>();
A forest is essentially a lookup table, it's the Tree that has a link to what forest the tree is in but I want to return a distinct list of forests. So in regular sql it would look like:
select f.*
from Forest f
inner join Tree t
on t.Forest_id = f.ID
where t.NumberOfTrees > 1000
If you have a relationship from Forest -> Trees then you can do this:
Forest f = null;
Tree t = null;
ForestsFound = session.QueryOver<Forest>(() => f)
.JoinAlias(() => f.Trees, () => t)
.Where(() => t.NumberOfTrees > 1000)
.List<Forest>();

complex search with thinking sphinx

I'd like to do a complex search with thinking sphinx:
Search for users which:
-> live in a city (city_id attribute)
-> or has hability to move to a city (mobile_cities association)
-> or live at a maximum distance from a lat/long point, the maximum distance is different for each user and set in a mobility_distance attribute.
For now I did that with 3 differents search, I volontary set a big per_page number, then i merge the 3 results on a single array, an then paginate this array :
#users living in the #city
search_set_living = search_set.merge({:city_id => #city.id })
users_living = User.search :with => search_set_living.dup,
:page => 1, :per_page => 1000
#users declaring hability to move to the #city
search_set_mobile = search_set.merge({:mobile_cities_ids => #city.id })
users_mobile = User.search :with => search_set_mobile.dup, :page => 1, :per_page => 1000
#users living at a maximum distance from the origin point(custom distance for each user, max 30km)
search_set_around = search_set.merge({"#geodist" => 0.0..30_000.0})
users_around = User.search :geo => [#search_latitude * Math::PI / 180 , #search_longitude * Math::PI / 180],
:with => search_set_around.dup,
:page => 1, :per_page => 1000
users_around_filtered = users_around.dup.delete_if{|user| (user.mobility_distance * 1000 )< user.sphinx_attributes['#geodist'] }
#merge the 3 results in a array
all_users = (users_mobile.flatten + users_around_filtered.flatten).uniq
#look for facets and paginate the array
#facets = User.facets :with => {:user_id => all_users.map(&:id)}
#users_to_display = all_users.paginate(:page => params[:page], :per_page => 10)
This is working fine but i'm not satisfied:
-performance are not so good,
-I want the ability to sort on multiple attributes like this :order => "created_at DESC, #relevance DESC"
I want to do the exact same search but in a single sphinx's search.
I know that I should use the "OR Logic with Attribute Filters" from the docs but I don't know how to mix it with a geo_search call...
I really have no idea how to do that,
can you guys help me ?
Many thanks,
The :sphinx_select option is definitely your friend here, as you've guessed. Let's piece it together bit by bit:
logic = [
"city_id = #{#city.id}",
"IN(mobile_cities_ids, #{#city.id}",
"GEODIST(lat, lng, #{lat}, #{lng}) < (mobility_distance * 1000)"
]
User.search :sphinx_select => "*, #{logic.join(" OR ")}) AS valid",
:with => {:valid => true}
Add pagination as you like, tweak the attribute names if needed (maybe your lat/lng attributes are named something else). I don't think you need the IF call around that custom attribute like in the docs, but if things aren't working when they should be, maybe give it a shot. Should be good in a facets call too.
Great ! Thank you so much. I just needed to correct a little your syntax (some parenthesis missing) in order to get it work.
I had to add per_page and page arguments too, don't know really why.
logic = ["city_id = #{#city.id}",
"IN(mobile_cities_ids, #{#city.id})",
"GEODIST(latitude, longitude, #{#search_latitude * Math::PI / 180}, #{#search_longitude * Math::PI / 180}) < (mobility_distance * 1000)"]
search_set_logic = search_set.merge({:valid => true})
#users_to_display = User.search :sphinx_select => "*, (#{logic.join(" OR ")}) AS valid",
:with => search_set_logic.dup,
:sort_mode => :extended,
:order => "visibility DESC, last_login_at DESC",
:page => params[:page], :per_page => 10