A periodic task that creates new encounters among all those who wish and have not yet met

Hey, everybody,
How to create a periodic task (performed once a day) that creates new meetings among all those who want to and have not yet met.

 schema "users" do
    field :email, :string
    field :name, :string
    field :surname, :string
    field :is_status, :boolean, default: true

    timestamps()
    
    has_many :meetup1, Meetup, foreign_key: :meetuper1
    has_many :meetup2, Meetup, foreign_key: :meetuper2
  end

-------
schema "meetups" do
    field :met_at, :naive_datetime
    field :users, {:array, :integer}, virtual: true
    field :meetuper1_rating, :integer
    field :meetuper2_rating, :integer
    field :average_rating, :float
    timestamps()

    belongs_to :user1, User, foreign_key: :meetuper1
    belongs_to :user2, User, foreign_key: :meetuper2
  end

You need to write query that creates cross-join between all people that hasn’t meet (beware that this will be quite expensive). Then create new entry for each resulting row.

After that write that as a script/function and run it using Cron or similar utility once a day.

I wrote a helper abtraction for that called Periodic. It is included in the parent library. See this docs section for details on fixed scheduling. I also wrote about periodic execution in more details in this blog post.

Finally, you can also look into quantum or oban.

4 Likes

You can also read here for a solution to a similar problem (not using Elixir nor Postgres, but it might help on the algorithm side):

Note that the implementation described there basically generates lots of candidate solutions and searches for the best, so it won’t be efficient in terms of minimizing computation. This might or might not be a good approach for your task, depending on your constraints and goals.

As long as the “wish to meet” is an explicit action from the user, you can avoid the cross-join that @hauleth correctly indicated as expensive by modeling the wish of users to meet with each other with a join table.

You could even reuse your meetups table, adding a boolean column that indicates whether a meetup was already scheduled, or it is just a “wish”. If you always sort the foreign keys meetuser1 and meetuser2 in your meetups (say by enforcing that meetuser1 is the one with the smallest ID), then you can enforce uniqueness of meetups between specific people by adding a unique index on [meetuser1, meetuser2].

Then, you can run a periodic job with something like Oban that would select a maximum number of meetups still in “wish” state, and actually schedule them.