12 changed files with 229 additions and 21 deletions
@ -0,0 +1,95 @@ |
|||||||
|
package net.sopod.soim.entry.delay; |
||||||
|
|
||||||
|
import com.google.common.base.Preconditions; |
||||||
|
import com.google.protobuf.MessageLite; |
||||||
|
import net.sopod.soim.common.util.ImClock; |
||||||
|
import net.sopod.soim.core.handler.MessageHandler; |
||||||
|
import net.sopod.soim.core.registry.ProtoMessageHandlerRegistry; |
||||||
|
import net.sopod.soim.core.session.NetUser; |
||||||
|
import net.sopod.soim.entry.server.ProtoMessageDispatcher; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import java.lang.ref.WeakReference; |
||||||
|
import java.util.concurrent.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* NetUserDelayTaskManager |
||||||
|
* 延时任务执行 |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-04-13 16:59 |
||||||
|
*/ |
||||||
|
public class NetUserDelayTaskManager { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(NetUserDelayTaskManager.class); |
||||||
|
|
||||||
|
private static final DelayQueue<DelayTask> DELAY_QUEUE; |
||||||
|
|
||||||
|
static { |
||||||
|
DELAY_QUEUE = new DelayQueue<>(); |
||||||
|
ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); |
||||||
|
scheduledExecutor.scheduleWithFixedDelay(() -> { |
||||||
|
try { |
||||||
|
DelayTask delayTask; |
||||||
|
// 连续批量执行50个任务
|
||||||
|
for (int i = 0; i < 50; i++) { |
||||||
|
delayTask = DELAY_QUEUE.poll(); |
||||||
|
if (delayTask == null) { |
||||||
|
break; |
||||||
|
} |
||||||
|
NetUser netUser = delayTask.getNetUser(); |
||||||
|
if (netUser != null && netUser.isActive()) { |
||||||
|
ProtoMessageDispatcher.dispatch(netUser, delayTask.getTaskMsg()); |
||||||
|
} else { |
||||||
|
logger.info("delayTask netUser inactive, task cancel!"); |
||||||
|
} |
||||||
|
} |
||||||
|
}catch (Throwable e) { |
||||||
|
logger.error("netUser delay task schedule error: ", e); |
||||||
|
} |
||||||
|
}, 100,100, TimeUnit.MILLISECONDS); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* TODO boolean netUser inactive cancel |
||||||
|
*/ |
||||||
|
public static void addTask(NetUser netUser, MessageLite taskMsg, long delay, TimeUnit unit) { |
||||||
|
Preconditions.checkNotNull(taskMsg); |
||||||
|
Preconditions.checkNotNull(unit); |
||||||
|
Preconditions.checkArgument(delay > 0, "延迟时间值必须大于0"); |
||||||
|
// 检查任务消息有无对应 handler 执行
|
||||||
|
MessageHandler<MessageLite> typeHandler = ProtoMessageHandlerRegistry.getTypeHandler(taskMsg.getClass()); |
||||||
|
if (typeHandler == null) { |
||||||
|
throw new IllegalStateException("not found taskMsg handler for type" + taskMsg.getClass() + "!"); |
||||||
|
} |
||||||
|
DELAY_QUEUE.add(new DelayTask(netUser, taskMsg, ImClock.millis() + unit.toMillis(delay))); |
||||||
|
} |
||||||
|
|
||||||
|
private static class DelayTask implements Delayed { |
||||||
|
// 如果 netUser 执行时不存在了,任务取消
|
||||||
|
private final WeakReference<NetUser> netUser; |
||||||
|
private final MessageLite taskMsg; |
||||||
|
private final long time; |
||||||
|
public DelayTask(NetUser netUser, MessageLite taskMsg, long time) { |
||||||
|
this.netUser = new WeakReference<>(netUser); |
||||||
|
this.taskMsg = taskMsg; |
||||||
|
this.time = time; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public long getDelay(TimeUnit timeUnit) { |
||||||
|
return time - ImClock.millis(); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public int compareTo(Delayed delayed) { |
||||||
|
return Long.compare(time, delayed.getDelay(TimeUnit.MILLISECONDS)); |
||||||
|
} |
||||||
|
public MessageLite getTaskMsg() { |
||||||
|
return this.taskMsg; |
||||||
|
} |
||||||
|
public NetUser getNetUser() { |
||||||
|
return netUser.get(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,64 @@ |
|||||||
|
package net.sopod.soim.entry.registry; |
||||||
|
|
||||||
|
import net.sopod.soim.common.util.ImClock; |
||||||
|
|
||||||
|
import java.util.concurrent.DelayQueue; |
||||||
|
import java.util.concurrent.Delayed; |
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
/** |
||||||
|
* DelayQueueTest |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-04-13 16:41 |
||||||
|
*/ |
||||||
|
public class DelayQueueTest { |
||||||
|
|
||||||
|
public static class DelayEle implements Delayed { |
||||||
|
|
||||||
|
private final TimeUnit unit; |
||||||
|
|
||||||
|
private final long time; |
||||||
|
|
||||||
|
public DelayEle(long delay, TimeUnit unit) { |
||||||
|
this.unit = unit; |
||||||
|
this.time = ImClock.millis() + unit.toMillis(delay); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getDelay(TimeUnit timeUnit) { |
||||||
|
System.out.println("[get delay]..." + this.time); |
||||||
|
return time - ImClock.millis(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int compareTo(Delayed delayed) { |
||||||
|
return Long.compare(this.time, delayed.getDelay(unit)); |
||||||
|
} |
||||||
|
|
||||||
|
public long getTime() { |
||||||
|
return this.time; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException { |
||||||
|
DelayQueue<Delayed> delayQueue = new DelayQueue<>(); |
||||||
|
DelayEle ele1 = new DelayEle(10, TimeUnit.SECONDS); |
||||||
|
DelayEle ele2 = new DelayEle(15, TimeUnit.SECONDS); |
||||||
|
DelayEle ele3 = new DelayEle(20, TimeUnit.SECONDS); |
||||||
|
delayQueue.add(ele1); |
||||||
|
delayQueue.add(ele2); |
||||||
|
delayQueue.add(ele3); |
||||||
|
for (int i = 0; i < 3;) { |
||||||
|
DelayEle ele = (DelayEle)delayQueue.poll(); |
||||||
|
if (ele != null) { |
||||||
|
System.out.println(ele.getTime()); |
||||||
|
i ++; |
||||||
|
} |
||||||
|
Thread.sleep(1000); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
package net.sopod.soim.entry.server; |
||||||
|
|
||||||
|
import com.google.protobuf.MessageLite; |
||||||
|
import net.sopod.soim.core.handler.MessageHandler; |
||||||
|
import net.sopod.soim.core.registry.ProtoMessageHandlerRegistry; |
||||||
|
import net.sopod.soim.core.session.NetUser; |
||||||
|
import net.sopod.soim.entry.worker.Worker; |
||||||
|
import net.sopod.soim.entry.worker.WorkerGroup; |
||||||
|
|
||||||
|
/** |
||||||
|
* ProtoMessageDispatcher |
||||||
|
* |
||||||
|
* @author tmy |
||||||
|
* @date 2022-04-13 17:21 |
||||||
|
*/ |
||||||
|
public class ProtoMessageDispatcher { |
||||||
|
|
||||||
|
public static void dispatch(NetUser netUser, MessageLite message) { |
||||||
|
MessageHandler<MessageLite> typeHandler = ProtoMessageHandlerRegistry |
||||||
|
.getTypeHandler(message.getClass()); |
||||||
|
Worker worker = WorkerGroup.next(); |
||||||
|
worker.execute(() -> { typeHandler.exec(netUser, message); }); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue