is a messaging pattern used to model an information exchange that implies the delivery (or spreading) of a message to one or multiple destinations possibly in parallel, and not halting the process that executes the messaging to wait for any response to that message.” Wikipedia: https://en.wikipedia.org/wiki/Fan-out_(software)
= @user.fetch_feed end end class User < ApplicationRecord def fetch_feed Post.eager_load(:user) .where(user: self.following + [self]) .order('posts.created_at DESC') end end
`users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 user.followers # => SELECT `users`.* FROM `users` INNER JOIN `connections` ON `users`.`id` = `connections`.`follower_id` WHERE `connections`.`following_id` = 4 user.following # => SELECT `users`.* FROM `users` INNER JOIN `connections` ON `users`.`id` = `connections`.`following_id` WHERE `connections`.`follower_id` = 4 user.fetch_feed # => User Load (0.4ms) SELECT `users`.* FROM `users` INNER JOIN `connections` ON `users`.`id` = `connections`.`following_id` WHERE `connections`.`follower_id` = 4 # => SQL (0.7ms) SELECT ..... FROM `posts` LEFT OUTER JOIN `users` ON `users`.`id` = `posts`.`user_id` WHERE `posts`.`user_id` IN (5, 4) ORDER BY posts.created_at DESC LIMIT 11
cache_key_for(id:) "cached_post/#{id}" end def id_from_cache_key(key:) key.split('/').last end def deliver_to_followers (user.followers + [user]).each do |follower| follower.add_to_cache(post: self) end end end
0, -1).map { |id| Post.cache_key_for(id: id) } return fetch_read_feed unless cache_keys.any? # Fall back to slow feed if there is no cache Rails.cache.fetch_multi(*cache_keys, expires: 1.minute, race_condition_ttl: 5.seconds) do |key| id = Post.id_from_cache_key(key: key) Post.find_by(id: id) end.values end def fetch_read_feed Post.eager_load(:user) .where(user: self.following + [self]) .order('posts.created_at DESC') end def add_to_cache(post:) redis.zadd(cache_key, post.created_at.to_i, post.id) end end
`users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 user.fetch_feed # => Post Load (5.9ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 21 LIMIT 1 # => Post Load (0.7ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 20 LIMIT 1 # => Post Load (0.6ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 19 LIMIT 1 # => Post Load (0.3ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 18 LIMIT 1 # => Post Load (0.3ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 17 LIMIT 1 # => Post Load (0.5ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 16 LIMIT 1 # => Post Load (0.4ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 15 LIMIT 1 # => Post Load (0.3ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 14 LIMIT 1
`users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 user.fetch_feed # => Post Load (5.9ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 21 LIMIT 1 # => Post Load (0.7ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 20 LIMIT 1 # => Post Load (0.6ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 19 LIMIT 1 JOINがなくなりました!