Medium Engineering

Stories from the team building Medium.

Follow publication

Counting your followers

An Vu
Medium Engineering
Published in
12 min readNov 24, 2020

Photo: Crissy Jarvis on Unsplash

What happens when you press the follow button?

Behind the scenes

Current scenario

putUserRelationship(
source_user_id: string,
target_user_id: string,
social_type: string
created_at: number
): Promise<boolean> {

// setting up the data
const relationship: Object = {
user_id: user_id,
target_user_id: target_user_id,
}
switch (social_type) {
case "TWITTER":
relationship.latest_followed_at = created_at
relationship.twitter_followed_at = created_at
case "FACEBOOK":
relationship.latest_followed_at = created_at
relationship.facebook_followed_at = created_at
case "MEDIUM":
relationship.latest_followed_at = created_at
relationship.medium_followed_at = created_at
case "UNFOLLOW":
relationship.latest_followed_at = 0
relationship.medium_unfollowed_at = created_at
// This function puts the data into the user relationship table
return this._socialData
.putUserRelationship(
relationship,
)
//this part updates the user stats table
.thenBound(this._updateUserCounts, this)
.then((): boolean => {
return true
})
}

Old Medium data

isFollowingRelation(relation) {  
const followedAt = Math.max(relation.medium_followed_at,
relation.twitter_followed_at,
relation.facebook_followed_at)
|| 0
return !relation.medium_followed_at ||
followedAt > relation.medium_unfollowed_at
}
Ev’s Medium Followers

The new column at the table (circa 2016)

The problem that prompted the backfills

The backfill that conked some numbers

Getting the data

with new_follow_updates as (
select
user_id,
target_user_id,
medium_unfollowed_at,
GREATEST(
twitter_followed_at,
facebook_followed_at,
medium_followed_at) as followed_at
from user_relations
where latest_followed_at = 0
and followed_at > 0
)
select user_id, target_user_id from new_follow_updates where followed_at > medium_unfollowed_at;
select 
user_id,
target_user_id
from user_relations
where
medium_unfollowed_at > 0
and latest_followed_at > 0
and medium_unfollowed_at > latest_followed_at;
Backfill workflow.

Problem

return this._userSocialData
.putUserRelationships(
relationships,
)
.thenBound(this._updateUserCounts, this) <--- Problem call
.then((): boolean => {
return true
})

The backfill that got it right

// This data will go into s3
followees_diff = user_stats_followees - user_relationships_followees
followers_diff = user_stats_followers - user_relationships_followers
// This calculation is done in the processor and goes into the database
final_followers = user_stats_followers + followers_difference
final_followees = user_stats_followees + followees_difference
with followees as (
select
user_id,
count(*) as followees
from user_relations
where
latest_followed_at > 0
group by 1
),
followers as (
select
target_user_id as user_id,
count(*) as followers
from user_relations
where
latest_followed_at > 0
group by 1
),
differences as (
select
user_id,
fe.followers as followers,
fr.followees as followees,
fe.followers - us.followers as diff_followers,
fr.followees - us.followees as diff_followees
from user_stats us
join followers fe using(user_id)
join followees fr using(user_id)
where
abs(diff_followers) > 0
or abs(diff_followees) > 0
order by diff_followers, diff_followees desc
)
select
user_id,
diff_followers,
diff_followees
from differences
user_id | diff_followers | diff_followees
------------------------------------------
abcde123| -10324| 0

Takeaways

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Responses (5)

Write a response