前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何设计一个任务管理器

如何设计一个任务管理器

原创
作者头像
被删
发布于 2024-08-04 12:07:04
发布于 2024-08-04 12:07:04
5060
举报

一般来说,我们在遇到对顺序要求严格的任务执行时,就需要维护一个任务管理器,保证任务的执行顺序。前端开发过程中,设计队列/栈的场景比较多,而需要用到任务管理器的场景偏少,本文主要介绍如何实现一个任务管理器。

理解任务管理器比较好的场景大概是协同文档编辑的场景,比如 Google Docs、腾讯文档、Sketch 协同等。我们在进行协同编辑的时候,对版本和消息时序有比较严格的要求,因此常常需要维护一个任务管理器来管理版本相关的任务。

以上是一些科普知识,用于辅助大家理解接下来的任务管理器设计,下面我们来进入正文。

单个任务的设计

对于单个任务的设计,主要考虑任务的执行。一个任务的作用就是用来运行的,那么对于任务来说,可能会有几个状态:待执行、正在执行、执行失败、执行成功等:

代码语言:ts
AI代码解释
复制
enum TASK_STATUS {
  INIT = "INIT", // 初始状态
  READY = "READY", // 可执行
  RUNNING = "RUNNING", // 执行中
  SUCCESS = "SUCCESS", // 执行成功
  FAILED = "FAILED", // 执行失败
  DESTROY = "DESTROY", // 已销毁
}

生命周期

既然涉及到任务的各个状态,我们也可以赋予任务一些生命周期。这里我们举一些例子,但最终的生命周期设计应该要和自己业务实际情况结合。

onReady: 任务执行前准备工作

在每个任务执行之前,我们都需要再次确认下这个任务的状态(是否已经失效),也可能需要做些准备工作,这个阶段可以命名为onReady

代码语言:ts
AI代码解释
复制
export interface ICommonTask {
  onReady(): Promise<boolean>;
}

可以看到,该生命周期以返回 Promise 的方式来运行,该 Promise 包括一个布尔值,用于判断任务是否继续执行。比如我们需要在执行任务之前,从服务端获取一些数据,那么可以这么实现:

代码语言:ts
AI代码解释
复制
class ATask implements ICommonTask {
  async onReady() {
    const result = await getSomeDate();
    if (result.isSuccess) {
      return true;
    }
    return false;
  }
}

onRun: 任务执行中

任务准备工作完成之后,任务就需要开始真正运行了。同样的,我们将这个阶段命名为onRun

代码语言:ts
AI代码解释
复制
export interface ICommonTask {
  onReady(): Promise<boolean>;
  onRun(): Promise<CommonTask[] | void>;
}

这里我们看到,onRun阶段执行同样返回一个 Promise,但 Promise 内容和onReady阶段不一致,它可能返回一个或者多个CommonTask组成的数组。这是因为一个任务执行的过程中,可能会产生新的任务,也可能由于其他条件限制,导致它需要创建一个别的任务先执行完毕,才能继续执行自己原本的任务。比如,B 任务在执行的时候,如果条件不满足,则需要先执行一个 A 任务:

代码语言:ts
AI代码解释
复制
class BTask implements ICommonTask {
  // 其他省略
  async onRun() {
    if (needATask) {
      return [new ATask(), this.resetTask()];
    }
    // 其他正常执行任务逻辑
  }
}

onDestroy: 任务执行完毕,即将销毁

很多时候我们实现一些模块功能,都会产生一些临时变量,也可能有一些事件绑定、DOM 元素需要在该模块注销的时候清除,因此进行主动的销毁和清理是一个很好的习惯。对于一个任务的执行来说也是一样的,我们将这个阶段命名为onDestroy

代码语言:ts
AI代码解释
复制
export interface ICommonTask {
  onReady(): Promise<boolean>;
  onRun(): Promise<CommonTask[] | void>;
  onDestroy(): Promise<void>;
}

对于任务的生命周期相关,我们暂时讲到这里,接下来我们来看任务的执行。

任务执行

由于每个任务都会有状态、生命周期、执行功能、重置功能,我们可以实现一个通用的任务:

代码语言:ts
AI代码解释
复制
abstract class CommonTask implements ICommonTask {
  /** 生命周期钩子 **/
  abstract onReady: () => Promise<boolean>;
  abstract onRun: () => Promise<CommonTask[] | void>;
  abstract onDestroy: () => Promise<void>;

  /** 执行任务 **/
  public async execute(): Promise<CommonTask[] | void> {
    // step 1 准备任务
    if (!(await this.onReady())) {
      // 任务准备校验不通过,直接没必要执行了
      return this.onDestroy();
    }
    // step 2 执行任务
    const runResult = await this.onRun();
    if (runResult) {
      // 若分裂出新的任务,返回并不再继续执行了
      return runResult;
    }
    // step 3 销毁任务
    this.onDestroy();
  }
}

这里 CommonTask 提供了一个通用的execute方法用于执行任务,我们能看到其中的实现也是根据生命周期依次执行。当然,这里其实还需要在执行到对应生命周期的时候,扭转任务状态。除此之外,任务执行异常的处理也并不在这里,因此外界需要进行try catch处理。

那么到底在哪里需要进行异常处理呢?我们接下来看看任务管理器。

任务管理器

显然,任务管理器的职责主要是保证任务队列中的任务有序、顺利地执行,其中会包括任务执行时的异常处理。除此之外,任务管理器还需要对外提供添加任务,以及暂停、恢复、停止这样的能力。

任务管理器状态

既然任务管理器有对任务的管理,当然它也需要维护自身的状态,例如:

代码语言:ts
AI代码解释
复制
enum QUEUE_STATUS {
  WORKING = "WORKING", // 工作中
  PAUSE = "PAUSE", // 暂停
  IDLE = "IDLE", // 空闲
  SHUTDOWN = "SHUTDOWN", // 关停
}

这些是任务管理器基本的状态,包括空闲状态、工作中、暂停、停止等。对于每一个不同的状态来说,相应的任务管理器也会有一些更新状态的方法:

代码语言:ts
AI代码解释
复制
class TaskManager {
  status: QUEUE_STATUS = QUEUE_STATUS.IDLE;
  // 暂停任务管理器
  public pause() {
    this.status = QUEUE_STATUS.PAUSE;
    // 当前正在运行的任务需要处理
  }
  // 恢复任务管理器
  public resume() {
    // 如果被关停了,则不能恢复啦
    if (isShutDown) {
      return;
    }
    this.status = QUEUE_STATUS.WORKING;
    this.work();
  }
  // 关停任务管理器
  public resume() {
    this.status = QUEUE_STATUS.SHUTDOWN;
  }
  // 任务管理器工作
  private work() {
    if (!isWorking && hasNextTask) {
      // 如果有会继续执行下一个任务
      // 直到任务管理器被暂停、或者任务队列为空
      runNextTask();
    }
  }
}

这里面比较关键的点有两个:

  1. 暂停任务管理器的时候,需要考虑如何处理正在运行的任务。
  2. 执行任务的时候,需要进行一些异常处理。同时,任务的运行可能会进行分裂并产生新的任务,需要对新任务进行处理。

暂停与恢复

我们先来看第一点:任务管理器暂停和恢复时的处理。

一个简单粗暴的处理方式是,将当前正在运行的任务继续运行完成。但这种处理方式,与我们对于暂停的理解有一些误差。因此,我们可以考虑让任务本身支持重置的功能,比如运行过程中判断任务状态是否需要继续执行,结合销毁当前任务、并将原有任务进行重置。

代码语言:ts
AI代码解释
复制
abstract class CommonTask {
  /** 重置任务 **/
  // 会返回任务本身,该任务应该是被重置过的最初状态
  abstract reset(): CommonTask;
}

实现起来其实也不会很难:

代码语言:ts
AI代码解释
复制
class ATask extends CommonTask {
  public reset() {
    // 销毁当前任务
    this.destroy();
    // 并返回一个重置后的新任务
    return new ATask();
  }
}

对于任务管理器来说,要做的事情也比较简单了:暂停任务管理器的时候,将当前任务重置、并扔回任务队列的头部。

代码语言:ts
AI代码解释
复制
class TaskManager {
  // 暂停任务管理器
  public pause() {
    this.status = QUEUE_STATUS.PAUSE;
    // 将当前任务重置,并扔回任务队列头部
    taskList.unshift(currentTask.reset());
  }
}

任务管理器工作

任务管理器工作的时候,主要工作内容包括依次运行任务、处理任务异常、处理任务运行后分裂产生的新任务。

代码语言:ts
AI代码解释
复制
class TaskManager {
  // 任务管理器工作
  private async work() {
    if (!isWorking && hasNextTask) {
      // 如果满足条件,会继续执行下一个任务
      currentTask = getNextTask();
      const resultTask = await currentTask.execute().catch((error) => {
        // 异常处理
      });
      // 判断是否有分裂的新任务
      if (resultTask) {
        // 如果有,就塞回到任务队列的头部,需要优先处理
        taskList.unshift(resultTask);
      }
      // 继续执行下一个任务
      checkContinueWork();
    }
  }
}

以上大概是我们在设计一个任务管理器的过程中,需要进行思考的一些问题、和简单的实现方式。除此之外,在一个更加复杂的应用场景下,我们还可能会遇到多个任务队列的管理和资源调度、同步任务和异步任务的管理、任务支持优先级设置等各式各样的功能设计。

结束语

任务管理也好、队列/堆栈的设计也好,都会在工程中经常遇到。而随着应用场景的不一样,我们的设计并不能简单地进行复用,每一次都可以结合业务本身、工程本身而设计出更加合适的调整,每一次我们也都可以给自己提出不一样的要求。

查看Github有更多内容噢: https://github.com/godbasin

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
内网学习笔记 | 6、ICMP隧道工具使用
在内网中,如果攻击者使用 HTTP、DNS 等应用层隧道都失败了,那么或许可以试试网络层的 ICMP 隧道,ICMP 协议最常见的场景就是使用 ping 命令,而且一般防火墙都不会禁止 ping 数据包。
TeamsSix
2021/04/12
1.7K0
内网转发及隐蔽隧道 | 网络层隧道技术之ICMP隧道(pingTunnel/IcmpTunnel)
ICMP隧道简单实用,是一个比较特殊的协议。在一般的通信协议里,如果两台设备要进行通信,肯定需要开放端口,而在ICMP协议下就不需要。最常见的ping命令就是利用的ICMP协议,攻击者可以利用命令行得到比回复更多的ICMP请求。在通常情况下,每个ping命令都有相应的回复与请求。
谢公子
2022/01/19
3.6K0
内网转发及隐蔽隧道 | 网络层隧道技术之ICMP隧道(pingTunnel/IcmpTunnel)
IMCP协议的魅力——IMCP隧道
1、ICMP隧道的建立同样是建立在ICMP未被防火墙禁用的情况下使用的,就是PING命令,其原理就是在ICMP报文传输的时候,替换其中的Data部分的数据,并且对端通过一样的工具进行ICMP畸形包的处理。从而将恶意流量隐藏在ICMP数据包中,形成ICMP隧道。
重生信息安全
2020/05/06
6630
内网隧道之ICMP隧道
ICMP是一个比较特殊的协议,在一般的通信协议里如果两台设备要进行通信,肯定需要开放端口,而在ICMP协议下就不需要,最常见的ICMP消息为ping命令的回复,攻击者可以利用命令行得到比回复更多的ICMP请求,在通常情况下,每个ping命令都有相对应的回复与请求
Al1ex
2022/09/07
2.8K0
内网隧道之ICMP隧道
内网基础-隐藏通信隧道技术
当我们在外网打下一个点,通过arp,netstat,以及ifconifg(ipconfig)等信息收集,发现此点为dmz,可通内网,那么这时候我们需要在此点上搭建通向内网的隧道,为内网渗透打下坚实基础。
Gamma实验室
2021/03/25
2.1K0
内网基础-隐藏通信隧道技术
内网转发及隐蔽隧道 | 使用ICMP进行命令控制(Icmpsh)
ICMP隧道简单实用,是一个比较特殊的协议。在一般的通信协议里,如果两台设备要进行通信,肯定需要开放端口,而在ICMP协议下就不需要。最常见的ping命令就是利用的ICMP协议,攻击者可以利用命令行得到比回复更多的ICMP请求。在通常情况下,每个ping命令都有相应的回复与请求。
谢公子
2022/01/19
8110
内网转发及隐蔽隧道 | 使用ICMP进行命令控制(Icmpsh)
ATT&CK视角下的红蓝对抗:十五.内网穿透之利用ICMP协议进行隧道穿透
本文介绍了利用ICMP协议进行隧道穿透的方法。ICMP协议不需要开放端口,可以将TCP/UDP数据封装到ICMP的Ping数据包中,绕过防火墙限制。常见的ICMP隧道穿透工具有Icmpsh、Icmptunnel、Pingtunnel等。本文以ICMPsh和Pingtunnel为例,介绍了如何利用ICMP协议进行隧道穿透。
一只特立独行的兔先生
2023/11/12
6110
ATT&CK视角下的红蓝对抗:十五.内网穿透之利用ICMP协议进行隧道穿透
内网渗透基石篇-- 隐藏通信隧道技术(上)
在实际的网络中,通常会通过各种边界设备、软/硬件防火墙甚至入侵检测系统来检查对外连接情况,如果发现异样,就会对通信进行阻断。那么什么是隧道呢?这里的隧道,就是一种绕过端口屏蔽的通信方式。防火墙两端的数据包通过防火墙所允许的数据包类型或端口进行封装,然后穿过防火墙,与对方进行通信。当封装的数据包到达目的地时,将数据包还原,并将还原后的数据包发送到相应服务器上。
顾翔
2021/05/17
2.6K0
内网渗透基石篇-- 隐藏通信隧道技术(上)
利用ICMP隧道加密隐藏通信Shell - 渗透红队笔记
ICMP隧道是一个比较特殊的协议。在一般的通信协议里,如果两台设备要进行通信,肯定要开放端口,而在ICMP协议下就不需要。最常见的ICMP消息为Ping命令的回复,攻击者可以利用命令得到比回复更多的ICMP请求。在通常情况下,每个Ping命令都有相对应的回复与请求。
渗透攻击红队
2020/11/25
1.7K0
利用ICMP隧道加密隐藏通信Shell - 渗透红队笔记
浅析Icmp原理及隐蔽攻击的方式
Internet Control Message Protocol Internet控制报文协议。它是TCP/IP协议簇的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用于网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用
FB客服
2021/10/21
2.4K0
内网渗透测试研究:隐藏通讯隧道技术
在实际的网络中,通常会通过各种边界设备、软/硬件防火墙甚至入侵检测系统来检查对外连接情况,如果发现异样,就会对通信进行阻断。那么什么是隧道呢?这里的隧道,就是一种绕过端口屏蔽的通信方式。防火墙两端的数据包通过防火墙所允许的数据包类型或端口进行封装,然后穿过防火墙,与对方进行通信。当封装的数据包到达目的地时,将数据包还原,并将还原后的数据包发送到相应服务器上。
FB客服
2020/07/09
2.1K0
内网渗透测试研究:隐藏通讯隧道技术
利用ICMP(icmpsh)协议反弹Shell - 渗透红队笔记
ICMP隧道是一个比较特殊的协议。在一般的通信协议里,如果两台设备要进行通信,肯定要开放端口,而在ICMP协议下就不需要。最常见的ICMP消息为Ping命令的回复,攻击者可以利用命令得到比回复更多的ICMP请求。在通常情况下,每个Ping命令都有相对应的回复与请求。
渗透攻击红队
2020/11/25
1.8K0
利用ICMP(icmpsh)协议反弹Shell - 渗透红队笔记
内网穿透之icmp隧道搭建+上线CS+环境场景搭建
在后渗透中内网隧道是必不可少的,在能够TCP出网的情况下搭建隧道是最容易的,使用frp即稳定又方便,搭建几级代理都不是问题。但是也有很多TCP不出网的情况,在这种场景下搭建隧道就要另寻门路了。为了方便学习内网隧道技术,我在公司的内网环境搭建了基于windows系统的苛刻的隧道环境,其实很简单,都是windows自带防火墙的一些规则策略。通过各种尝试,终于完成此环境(不知道有没有别的问题),现在把过程分享给大家~路过的师傅都来看看呀,有不正确的地方求教教我^^
亿人安全
2022/06/30
2.5K0
内网穿透之icmp隧道搭建+上线CS+环境场景搭建
渗透测试战技101之nmap与icmp隧道
知识触发战技,战技刻意练习得到经验,经验反思源头,得到创新力。我们需要模仿与练习。——-sec875
FB客服
2021/08/24
7520
【内网安全】隧道技术&SSH&DNS&ICMP&SMB&上线通讯Linux&Mac
判断:445通讯 通过端口扫描是否开放445端口进行判断 上线:借助通讯后绑定上线 详见往期文章 通讯:直接SMB协议通讯即可
没事就要多学习
2024/07/18
2570
【内网安全】隧道技术&SSH&DNS&ICMP&SMB&上线通讯Linux&Mac
基于统计分析的ICMP隧道检测方法与实现
在企业内网环境中,ICMP协议是必不可少的网络通信协议之一,被用于检测网络连通状态,通常情况下,防火墙会默认放此协议。由于防火墙对ICMP协议开放,恶意攻击者常会利用ICMP协议进行非法通信。例如,在黑客攻击中经常出现一种情况是,黑客通过某一种方式取得了一台主机的权限,得到了一些文件,比如域hash,密码文件之类的东西,需要回传至本地进行破解,但是防火墙阻断了由内网发起的请求,只有icmp协议没有被阻断,而黑客又需要回传文件,这个时候如果黑客可以ping通远程计算机,就可以尝试建立ICMP隧道,ICMP隧道是将流量封装进 ping 数据包中,旨在利用 ping数据穿透防火墙的检测。现在市面上已经有了很多类似的工具了,比如 icmptunnel、ptunnel、icmpsh等。
FB客服
2019/05/15
2K0
基于统计分析的ICMP隧道检测方法与实现
通过ICMP协议反弹SHELL并执行命令
内网中的大多数系统都位于防火墙和企业代理之后,以便控制入口以及出口流量。防火墙可以拦截到反连的shell,但ICMP协议基本上是不拦截的。因此,为了获得shell并在目标主机上执行命令,可以使用ICMP协议作为隐藏通道进行连接。
Ms08067安全实验室
2019/12/18
1.1K0
通过ICMP协议反弹SHELL并执行命令
内网隧道之icmpsh
最后更新于2013年,能通过ICMP协议请求/回复报文反弹cmd,不需要指定服务或者端口,也不用管理员权限,但反弹回来的cmd极不稳定
中龙技术
2022/09/29
5450
内网隧道之icmpsh
内网转发及隐蔽隧道 | 使用DNS进行命令控制(dnscat2)
dnscat2是一款开源软件,使用DNS协议创建加密的C&C通道,通过预共享密钥进行身份验证;使用Shell及DNS查询类型(TXT、MX、CNAME、A、AAAA),多个同时进行的会话类似于SSH中的隧道。dnscat2的客户端是有Windows版和Linux版,服务端是用Ruby语言编写的。严格的说,dnscat2是一个命令与控制工具。
谢公子
2022/01/19
4.5K0
内网转发及隐蔽隧道 | 使用DNS进行命令控制(dnscat2)
内网隧道穿透之流量检测与防护
在真实环境中,ICMP协议经常会被用来检测网络连通状态,而防火墙是会默认允许ICMP协议通信,因此越来越多的攻击者会利用ICMP协议进行非法通信,通过ICMP协议搭建隐蔽隧道加密恶意流量,从而对企业内网进行攻击。
一只特立独行的兔先生
2024/02/15
1.1K1
相关推荐
内网学习笔记 | 6、ICMP隧道工具使用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档