diff --git a/src/api/following/delete.ts b/src/api/following/delete.ts
new file mode 100644
index 0000000000..4cdff7ce1b
--- /dev/null
+++ b/src/api/following/delete.ts
@@ -0,0 +1,69 @@
+import User, { isLocalUser, isRemoteUser, pack as packUser, IUser } from '../../models/user';
+import Following from '../../models/following';
+import FollowingLog from '../../models/following-log';
+import FollowedLog from '../../models/followed-log';
+import event from '../../publishers/stream';
+import context from '../../remote/activitypub/renderer/context';
+import renderFollow from '../../remote/activitypub/renderer/follow';
+import renderUndo from '../../remote/activitypub/renderer/undo';
+import { createHttp } from '../../queue';
+
+export default async function(follower: IUser, followee: IUser, activity?) {
+	const following = await Following.findOne({
+		followerId: follower._id,
+		followeeId: followee._id
+	});
+
+	if (following == null) {
+		console.warn('フォロー解除がリクエストされましたがフォローしていませんでした');
+		return;
+	}
+
+	Following.remove({
+		_id: following._id
+	});
+
+	//#region Decrement following count
+	User.update({ _id: follower._id }, {
+		$inc: {
+			followingCount: -1
+		}
+	});
+
+	FollowingLog.insert({
+		createdAt: following.createdAt,
+		userId: follower._id,
+		count: follower.followingCount - 1
+	});
+	//#endregion
+
+	//#region Decrement followers count
+	User.update({ _id: followee._id }, {
+		$inc: {
+			followersCount: -1
+		}
+	});
+	FollowedLog.insert({
+		createdAt: following.createdAt,
+		userId: followee._id,
+		count: followee.followersCount - 1
+	});
+	//#endregion
+
+	// Publish unfollow event
+	if (isLocalUser(follower)) {
+		packUser(followee, follower).then(packed => event(follower._id, 'unfollow', packed));
+	}
+
+	if (isLocalUser(follower) && isRemoteUser(followee)) {
+		const content = renderUndo(renderFollow(follower, followee));
+		content['@context'] = context;
+
+		createHttp({
+			type: 'deliver',
+			user: follower,
+			content,
+			to: followee.account.inbox
+		}).save();
+	}
+}
diff --git a/src/queue/processors/http/unfollow.ts b/src/queue/processors/http/unfollow.ts
deleted file mode 100644
index 801a3612a7..0000000000
--- a/src/queue/processors/http/unfollow.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import FollowedLog from '../../../models/followed-log';
-import Following from '../../../models/following';
-import FollowingLog from '../../../models/following-log';
-import User, { isLocalUser, isRemoteUser, pack as packUser } from '../../../models/user';
-import stream from '../../../publishers/stream';
-import renderFollow from '../../../remote/activitypub/renderer/follow';
-import renderUndo from '../../../remote/activitypub/renderer/undo';
-import context from '../../../remote/activitypub/renderer/context';
-import request from '../../../remote/request';
-import Logger from '../../../utils/logger';
-
-export default async ({ data }) => {
-	const following = await Following.findOne({ _id: data.id });
-	if (following === null) {
-		return;
-	}
-
-	const [follower, followee] = await Promise.all([
-		User.findOne({ _id: following.followerId }),
-		User.findOne({ _id: following.followeeId })
-	]);
-
-	if (isLocalUser(follower) && isRemoteUser(followee)) {
-		const undo = renderUndo(renderFollow(follower, followee));
-		undo['@context'] = context;
-
-		await request(follower, followee.account.inbox, undo);
-	}
-
-	try {
-		await Promise.all([
-			// Delete following
-			Following.findOneAndDelete({ _id: data.id }),
-
-			// Decrement following count
-			User.update({ _id: follower._id }, { $inc: { followingCount: -1 } }),
-			FollowingLog.insert({
-				createdAt: new Date(),
-				userId: follower._id,
-				count: follower.followingCount - 1
-			}),
-
-			// Decrement followers count
-			User.update({ _id: followee._id }, { $inc: { followersCount: -1 } }),
-			FollowedLog.insert({
-				createdAt: new Date(),
-				userId: followee._id,
-				count: followee.followersCount - 1
-			})
-		]);
-
-		if (isLocalUser(follower)) {
-			return;
-		}
-
-		const promisedPackedUser = packUser(followee, follower);
-
-		// Publish follow event
-		stream(follower._id, 'unfollow', promisedPackedUser);
-	} catch (error) {
-		Logger.error(error.toString());
-	}
-};
diff --git a/src/remote/activitypub/act/create.ts b/src/remote/activitypub/act/create.ts
index 957900900f..c486571fc1 100644
--- a/src/remote/activitypub/act/create.ts
+++ b/src/remote/activitypub/act/create.ts
@@ -1,5 +1,4 @@
 import { JSDOM } from 'jsdom';
-const createDOMPurify = require('dompurify');
 
 import Resolver from '../resolver';
 import DriveFile from '../../../models/drive-file';
diff --git a/src/remote/activitypub/act/index.ts b/src/remote/activitypub/act/index.ts
index d78335f16e..f22500acef 100644
--- a/src/remote/activitypub/act/index.ts
+++ b/src/remote/activitypub/act/index.ts
@@ -2,25 +2,24 @@ import create from './create';
 import performDeleteActivity from './delete';
 import follow from './follow';
 import undo from './undo';
-import Resolver from '../resolver';
 import { IObject } from '../type';
 
-export default async (parentResolver: Resolver, actor, activity: IObject): Promise<void> => {
+export default async (actor, activity: IObject): Promise<void> => {
 	switch (activity.type) {
 	case 'Create':
-		await create(parentResolver, actor, activity);
+		await create(actor, activity);
 		break;
 
 	case 'Delete':
-		await performDeleteActivity(parentResolver, actor, activity);
+		await performDeleteActivity(actor, activity);
 		break;
 
 	case 'Follow':
-		await follow(parentResolver, actor, activity);
+		await follow(actor, activity);
 		break;
 
 	case 'Undo':
-		await undo(parentResolver, actor, activity);
+		await undo(actor, activity);
 		break;
 
 	default:
diff --git a/src/remote/activitypub/act/undo.ts b/src/remote/activitypub/act/undo.ts
new file mode 100644
index 0000000000..b3b83777d1
--- /dev/null
+++ b/src/remote/activitypub/act/undo.ts
@@ -0,0 +1,15 @@
+import unfollow from './unfollow';
+
+export default async (actor, activity): Promise<void> => {
+	if ('actor' in activity && actor.account.uri !== activity.actor) {
+		throw new Error('invalid actor');
+	}
+
+	switch (activity.object.type) {
+		case 'Follow':
+			unfollow(activity.object);
+			break;
+	}
+
+	return null;
+};
diff --git a/src/remote/activitypub/act/undo/index.ts b/src/remote/activitypub/act/undo/index.ts
deleted file mode 100644
index aa60d3a4fa..0000000000
--- a/src/remote/activitypub/act/undo/index.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import act from '../../act';
-import deleteObject from '../../delete';
-import unfollow from './unfollow';
-import Resolver from '../../resolver';
-
-export default async (resolver: Resolver, actor, activity): Promise<void> => {
-	if ('actor' in activity && actor.account.uri !== activity.actor) {
-		throw new Error();
-	}
-
-	const results = await act(resolver, actor, activity.object);
-
-	await Promise.all(results.map(async promisedResult => {
-		const result = await promisedResult;
-
-		if (result === null || await deleteObject(result) !== null) {
-			return;
-		}
-
-		switch (result.object.$ref) {
-		case 'following':
-			await unfollow(result.object);
-		}
-	}));
-
-	return null;
-};
diff --git a/src/remote/activitypub/act/undo/unfollow.ts b/src/remote/activitypub/act/undo/unfollow.ts
deleted file mode 100644
index c17e06e8a9..0000000000
--- a/src/remote/activitypub/act/undo/unfollow.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import queue from '../../../../queue';
-
-export default ({ $id }) => new Promise((resolve, reject) => {
-	queue.create('http', { type: 'unfollow', id: $id }).save(error => {
-		if (error) {
-			reject(error);
-		} else {
-			resolve();
-		}
-	});
-});
diff --git a/src/remote/activitypub/act/unfollow.ts b/src/remote/activitypub/act/unfollow.ts
new file mode 100644
index 0000000000..e3c9e1c1c8
--- /dev/null
+++ b/src/remote/activitypub/act/unfollow.ts
@@ -0,0 +1,25 @@
+import parseAcct from '../../../acct/parse';
+import User from '../../../models/user';
+import config from '../../../config';
+import unfollow from '../../../api/following/delete';
+
+export default async (actor, activity): Promise<void> => {
+	const prefix = config.url + '/@';
+	const id = activity.object.id || activity.object;
+
+	if (!id.startsWith(prefix)) {
+		return null;
+	}
+
+	const { username, host } = parseAcct(id.slice(prefix.length));
+	if (host !== null) {
+		throw new Error();
+	}
+
+	const followee = await User.findOne({ username, host });
+	if (followee === null) {
+		throw new Error();
+	}
+
+	await unfollow(actor, followee, activity);
+};