diff --git a/package-lock.json b/package-lock.json
index c3c73ec5a86ec1dd109bfca82f5dca35ab4066bc..8990ae98a097da0b5bd3cd745519e4ff5d9382b7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "matrix-appservice-discord",
-  "version": "0.4.0",
+  "version": "0.5.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -180,11 +180,6 @@
       "integrity": "sha512-Fvm24+u85lGmV4hT5G++aht2C5I4Z4dYlWZIh62FAfFO/TfzXtPpoLI6I7AuBWkIFqZCnhFOoTT7RjjaIL5Fjg==",
       "dev": true
     },
-    "@types/p-queue": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/@types/p-queue/-/p-queue-3.0.0.tgz",
-      "integrity": "sha512-brMFTEZiltJnAxNy07LzRVw2bdQX1ElCElHEmo5WEI70oWQe00aXew9RKmpf8MOzBMiMfNeuQoEyQCWKawPzmQ=="
-    },
     "@types/sqlite3": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/@types/sqlite3/-/sqlite3-3.1.3.tgz",
@@ -1014,15 +1009,15 @@
       }
     },
     "discord.js": {
-      "version": "11.4.2",
-      "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz",
-      "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==",
+      "version": "11.5.0",
+      "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.5.0.tgz",
+      "integrity": "sha512-7TAyr2p1ZP9k4gaIhQWOxZpybznT6ND55HbhntUqwQqXkAjIxU3ATbwiOSuCMd4AXz7L9wk1rioRL0sOjXs5CA==",
       "requires": {
         "long": "^4.0.0",
         "prism-media": "^0.0.3",
         "snekfetch": "^3.6.4",
         "tweetnacl": "^1.0.0",
-        "ws": "^4.0.0"
+        "ws": "^6.0.0"
       }
     },
     "doctrine": {
@@ -1353,6 +1348,11 @@
         "es5-ext": "~0.10.14"
       }
     },
+    "eventemitter3": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
+      "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
+    },
     "execa": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
@@ -3054,9 +3054,12 @@
       }
     },
     "p-queue": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-3.0.0.tgz",
-      "integrity": "sha512-2tv/MRmPXfmfnjLLJAHl+DdU8p2DhZafAnlpm/C/T5BpF5L9wKz5tMin4A4N2zVpJL2YMhPlRmtO7s5EtNrjfA=="
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-5.0.0.tgz",
+      "integrity": "sha512-6QfeouDf236N+MAxHch0CVIy8o/KBnmhttKjxZoOkUlzqU+u9rZgEyXH3OdckhTgawbqf5rpzmyR+07+Lv0+zg==",
+      "requires": {
+        "eventemitter3": "^3.1.0"
+      }
     },
     "p-try": {
       "version": "2.2.0",
@@ -4141,9 +4144,9 @@
       }
     },
     "tweetnacl": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz",
-      "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins="
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz",
+      "integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A=="
     },
     "type-check": {
       "version": "0.3.2",
@@ -4452,12 +4455,11 @@
       }
     },
     "ws": {
-      "version": "4.1.0",
-      "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz",
-      "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
+      "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
       "requires": {
-        "async-limiter": "~1.0.0",
-        "safe-buffer": "~5.1.0"
+        "async-limiter": "~1.0.0"
       }
     },
     "xtend": {
diff --git a/package.json b/package.json
index d0addede45c4c2aa5eba11d3119dbc0b10eb905d..4e19eaafab2e26daad71163d7d7bdf4ea1839f68 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "matrix-appservice-discord",
-  "version": "0.4.0",
+  "version": "0.5.0-rc2",
   "description": "A bridge between Matrix and Discord",
   "main": "discordas.js",
   "scripts": {
@@ -34,20 +34,18 @@
   },
   "homepage": "https://github.com/Half-Shot/matrix-appservice-discord#readme",
   "dependencies": {
-    "@types/p-queue": "^3.0.0",
     "better-sqlite3": "^5.0.1",
     "command-line-args": "^4.0.1",
     "command-line-usage": "^4.1.0",
     "discord-markdown": "^2.0.0",
-    "discord.js": "^11.4.2",
+    "discord.js": "^11.5.0",
     "escape-html": "^1.0.3",
     "escape-string-regexp": "^1.0.5",
     "js-yaml": "^3.13.1",
     "matrix-appservice-bridge": "matrix-org/matrix-appservice-bridge#8a7288edf1d1d1d1395a83d330d836d9c9bf1e76",
     "mime": "^1.6.0",
-    "moment": "^2.22.2",
     "node-html-parser": "^1.1.11",
-    "p-queue": "^3.0.0",
+    "p-queue": "^5.0.0",
     "pg-promise": "^8.5.1",
     "tslint": "^5.11.0",
     "typescript": "^3.1.3",
diff --git a/src/bot.ts b/src/bot.ts
index ab5abffae88099bacdb8612e3675823c964def2e..2c7ec056e84340912f46988dd067875841472b48 100644
--- a/src/bot.ts
+++ b/src/bot.ts
@@ -81,8 +81,8 @@ export class DiscordBot {
 
     /* Handles messages queued up to be sent to matrix from discord. */
     private discordMessageQueue: { [channelId: string]: Promise<void> };
-    private channelLocks: { [channelId: string]: {p: Promise<{}>, i: NodeJS.Timeout|null} };
-
+    private channelLocks: Map<string, {i: NodeJS.Timeout|null, r: (() => void)|null}>;
+    private channelLockPromises: Map<string, Promise<{}>>;
     constructor(
         private botUserId: string,
         private config: DiscordBridgeConfig,
@@ -106,7 +106,8 @@ export class DiscordBot {
         // init vars
         this.sentMessages = [];
         this.discordMessageQueue = {};
-        this.channelLocks = {};
+        this.channelLocks = new Map();
+        this.channelLockPromises = new Map();
         this.lastEventIds = {};
     }
 
@@ -139,34 +140,39 @@ export class DiscordBot {
     }
 
     public lockChannel(channel: Discord.Channel) {
-        if (this.channelLocks[channel.id]) {
+        if (this.channelLocks.has(channel.id)) {
             return;
         }
 
+        this.channelLocks[channel.id] = {i: null, r: null, p: null};
         const p = new Promise((resolve) => {
-            if (!this.channelLocks[channel.id]) {
-                resolve();
-                return;
-            }
-            const i = setInterval(resolve, this.config.limits.discordSendDelay);
-            this.channelLocks[channel.id].i = i;
+            const i = setTimeout(() => {
+                log.warn(`Lock on channel ${channel.id} expired. Discord is lagging behind?`);
+                this.unlockChannel(channel);
+            }, this.config.limits.discordSendDelay);
+            const o = Object.assign({r: resolve, i, p: null}, this.channelLocks.get(channel.id) || {});
+            this.channelLocks.set(channel.id, o);
         });
-
-        this.channelLocks[channel.id] = {i: null, p};
+        this.channelLockPromises.set(channel.id, p);
     }
 
     public unlockChannel(channel: Discord.Channel) {
-        const lock = this.channelLocks[channel.id];
-        if (lock && lock.i !== null) {
+        if (!this.channelLocks.has(channel.id)) {
+            return;
+        }
+        const lock = this.channelLocks.get(channel.id)!;
+        if (lock.i !== null) {
+            lock.r!();
             clearTimeout(lock.i);
         }
-        delete this.channelLocks[channel.id];
+        this.channelLocks.delete(channel.id);
+        this.channelLockPromises.delete(channel.id);
     }
 
     public async waitUnlock(channel: Discord.Channel) {
-        const lock = this.channelLocks[channel.id];
-        if (lock) {
-            await lock.p;
+        const promise = this.channelLockPromises.get(channel.id);
+        if (promise) {
+            await promise;
         }
     }
 
@@ -439,7 +445,7 @@ export class DiscordBot {
         try {
             this.lockChannel(chan);
             if (!botUser) {
-                opts.embed = embedSet.replyEmbed;
+                // NOTE: Don't send replies to discord if we are a puppet.
                 msg = await chan.send(embed.description, opts);
             } else if (hook) {
                 msg = await hook.send(embed.description, {
diff --git a/src/log.ts b/src/log.ts
index 11c86888f23a6cfa5a4dcd90ff0ad1bc6e355840..0477d8a1af5e77d3e47289f56a034a6afc3248e3 100644
--- a/src/log.ts
+++ b/src/log.ts
@@ -17,7 +17,6 @@ limitations under the License.
 import { createLogger, Logger, format, transports } from "winston";
 import { DiscordBridgeConfigLogging, LoggingFile} from "./config";
 import { inspect } from "util";
-import * as moment from "moment";
 import "winston-daily-rotate-file";
 
 const FORMAT_FUNC = format.printf((info) => {
@@ -47,10 +46,6 @@ export class Log {
     private static config: DiscordBridgeConfigLogging;
     private static logger: Logger;
 
-    private static now() {
-        return moment().format(Log.config.lineDateFormat);
-    }
-
     private static setupLogger() {
         if (Log.logger) {
             Log.logger.close();
@@ -64,7 +59,7 @@ export class Log {
         Log.logger = createLogger({
             format: format.combine(
                 format.timestamp({
-                    format: Log.now,
+                    format: Log.config.lineDateFormat,
                 }),
                 format.colorize(),
                 FORMAT_FUNC,
diff --git a/src/matrixeventprocessor.ts b/src/matrixeventprocessor.ts
index 3e39518ed5680ab4b38ac8355d2b90b28882b999..5751c8d962edca82431fd663075cfe55a41dd18f 100644
--- a/src/matrixeventprocessor.ts
+++ b/src/matrixeventprocessor.ts
@@ -196,31 +196,28 @@ export class MatrixEventProcessor {
 
         let msg = `\`${event.sender}\` `;
 
+        const isNew = event.unsigned === undefined || event.unsigned.prev_content === undefined;
+        const allowJoinLeave = !this.config.bridge.disableJoinLeaveNotifications;
+
         if (event.type === "m.room.name") {
             msg += `set the name to \`${event.content!.name}\``;
         } else if (event.type === "m.room.topic") {
             msg += `set the topic to \`${event.content!.topic}\``;
         } else if (event.type === "m.room.member") {
             const membership = event.content!.membership;
-            if (membership === "join"
-                && event.unsigned.prev_content === undefined) {
-                    if (!this.config.bridge.disableJoinLeaveNotifications) {
-                        msg += `joined the room`;
-                    } else {
-                        return;
-                    }
+            if (membership === "join" && isNew && allowJoinLeave) {
+                msg += "joined the room";
             } else if (membership === "invite") {
                 msg += `invited \`${event.state_key}\` to the room`;
             } else if (membership === "leave" && event.state_key !== event.sender) {
                 msg += `kicked \`${event.state_key}\` from the room`;
-            } else if (membership === "leave") {
-                if (!this.config.bridge.disableJoinLeaveNotifications) {
-                    msg += `left the room`;
-                } else {
-                    return;
-                }
+            } else if (membership === "leave" && allowJoinLeave) {
+                msg += "left the room";
             } else if (membership === "ban") {
                 msg += `banned \`${event.state_key}\` from the room`;
+            } else {
+                // Ignore anything else
+                return;
             }
         }
 
diff --git a/test/test_discordbot.ts b/test/test_discordbot.ts
index 4dd1ad806e8173127c73e73aaaad0d00f93b44ec..f6208be1d18c3d8d32377f56c27a94458ddcde8f 100644
--- a/test/test_discordbot.ts
+++ b/test/test_discordbot.ts
@@ -25,6 +25,7 @@ import { DiscordBot } from "../src/bot";
 import { MockDiscordClient } from "./mocks/discordclient";
 import { MockMessage } from "./mocks/message";
 import { Util } from "../src/util";
+import { MockChannel } from "./mocks/channel";
 
 // we are a test file and thus need those
 /* tslint:disable:no-unused-expression max-file-line-count no-any */
@@ -415,6 +416,46 @@ describe("DiscordBot", () => {
             assert.equal(expected, ITERATIONS);
         });
     });
+    describe("locks", () => {
+        it("should lock and unlock a channel", async () => {
+            const bot = new modDiscordBot.DiscordBot(
+                "",
+                config,
+                mockBridge,
+                {},
+            ) as DiscordBot;
+            const chan = new MockChannel("123") as any;
+            const t = Date.now();
+            bot.lockChannel(chan);
+            await bot.waitUnlock(chan);
+            const diff = Date.now() - t;
+            expect(diff).to.be.greaterThan(config.limits.discordSendDelay - 1);
+        });
+        it("should lock and unlock a channel early, if unlocked", async () => {
+            const discordSendDelay = 500;
+            const SHORTDELAY = 100;
+            const bot = new modDiscordBot.DiscordBot(
+                "",
+                {
+                    bridge: {
+                        domain: "localhost",
+                    },
+                    limits: {
+                        discordSendDelay,
+                    },
+                },
+                mockBridge,
+                {},
+            ) as DiscordBot;
+            const chan = new MockChannel("123") as any;
+            setTimeout(() => bot.unlockChannel(chan), SHORTDELAY);
+            const t = Date.now();
+            bot.lockChannel(chan);
+            await bot.waitUnlock(chan);
+            const diff = Date.now() - t;
+            expect(diff).to.be.greaterThan(SHORTDELAY - 1);
+        });
+    });
   // });
     // describe("ProcessMatrixMsgEvent()", () => {
     //
diff --git a/test/test_matrixeventprocessor.ts b/test/test_matrixeventprocessor.ts
index dd1a5d2e543b6740a5079750921b3af2626d472d..e5dbf0c9f14582bd47369391de7938d4f568a628 100644
--- a/test/test_matrixeventprocessor.ts
+++ b/test/test_matrixeventprocessor.ts
@@ -748,7 +748,8 @@ This is the reply`,
                 sender: "@test:localhost",
                 type: "m.room.message",
             } as IMatrixEvent, mockChannel as any);
-            expect(result!.timestamp!.getTime()).to.be.equal(TEST_TIMESTAMP);
+            // NOTE: Due to https://github.com/discordjs/discord.js/issues/3283, the typing is wrong here.
+            expect(result!.timestamp!).to.be.equal(TEST_TIMESTAMP);
         });
         it("should add field for discord replies", async () => {
             const processor = createMatrixEventProcessor();