๋‚˜๋งŒ์˜ ์ฒดํฌํฌ์ธํŠธ

๋ฌธ์ œ 1

  • ๋ถ„์„ ๋ฐ ์„ค๊ณ„ โœ… 2024-07-29
  • EventQueue ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • EventManager ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • EventLoop ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • Post ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • PostMan ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • PostHub ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29

๋ฌธ์ œ 2

  • ๋ถ„์„ ๋ฐ ์„ค๊ณ„ โœ… 2024-07-29
  • EventQueue ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • EventManager ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • EventLoop ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • Post ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • PostMan ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • PostHub ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ โœ… 2024-07-29
  • ์ž…๋ ฅ ๋ฐ›๊ธฐ โœ… 2024-07-30
  • ๋ฐฐ๋‹ฌ์› ์Šค์ผ€์ค„๋ง

๋ฌธ์ œํ•ด๊ฒฐ๊ณผ์ •

๋ถ„์„ ๋ฐ ์„ค๊ณ„

๋™์ž‘ ํ๋ฆ„

์šฐ์„  ๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ๋™์ž‘์˜ ํ๋ฆ„์€ ์ด์™€ ๊ฐ™๋‹ค.

  1. POS๋ฅผ ํ†ตํ•ด ํƒ๋ฐฐ ์ •๋ณด๋ฅผ Event queue(POS ์ ‘์ˆ˜ ๋Œ€๊ธฐ ํ)์— enqueueํ•œ๋‹ค.
  2. POS ์ ‘์ˆ˜ ๋Œ€๊ธฐ ํ์˜ ๋ฐฐ์†ก ๋ชฉ๋ก์€ ๋ฐฐ์†ก ๋งค๋‹ˆ์ €๊ฐ€ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ๋ฅผ ํ™•์ธํ•œ ๋’ค ๋งŒ์•ฝ ํ์— ๋Œ€๊ธฐ๋ชฉ๋ก์ด ์žˆ๋‹ค๋ฉด ๋ฌผ๋ฅ˜์„ผํ„ฐ๋กœ ๋ณด๋ƒ„
  3. ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์ฃผ๊ธฐ์ ์œผ๋กœ ๋Œ๋ฉด์„œ ๊ณ„์†ํ•ด์„œ ๋ฌผ๋ฅ˜์„ผํ„ฐ์— ์ „๋‹ฌ๋œ ๋ฌผํ’ˆ ์ด๋ฒคํŠธ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๋ฌผ๋ฅ˜์„ผํ„ฐ ํ์˜ ๋ถ„๋ฅ˜ ๋Œ€๊ธฐ ์ƒํƒœ๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ๋Œ€๊ธฐ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ๋ฌผ๋ฅ˜์„ผํ„ฐ ํ๋กœ ๋ฌผ๋ฅ˜๋ฅผ ๋ณด๋‚ธ๋‹ค.
  4. ๋ฌผ๋ฅ˜์„ผํ„ฐ์˜ ๋ฌผ๋ฅ˜์™€ ๋ฐฐ์†ก์›์˜ ์ƒํƒœ๋ฅผ boolean๊ฐ’์œผ๋กœ ๋‘๊ณ , ๋™์ž‘์ด ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•˜๋ฉด์„œ ๋™์ž‘์ด ๊ฐ€๋Šฅํ•  ๊ฒฝ์šฐ ์Œ“์—ฌ์žˆ๋˜ ์ด๋ฒคํŠธ๋ฅผ ํ•˜๋‚˜์”ฉ ๋ณด๋ƒ„

์—ฌ๊ธฐ์„œ ๋ฐฐ๋‹ฌ ๊ธฐ์‚ฌ๋‚˜ ๋ฌผ๋ฅ˜์„ผํ„ฐ ์ง์›์˜ ๊ฒฝ์šฐ ํ•œ ๋ฒˆ์— 1๊ฐœ์˜ ๋ฌผํ’ˆ๋งŒ ๋ฐฐ๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, 1๋ฒˆ์˜ ๊ฒฝ์šฐ์—๋Š” ๋ฐฐ๋‹ฌ๊ธฐ์‚ฌ๊ฐ€ 1๋ช…์ด๋ผ๋Š” ๊ฐ€์ • ํ•˜์— ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๊ธฐ์กด ๋ฐฐ๋‹ฌ์ด ์™„๋ฃŒ๋˜๊ธฐ๊นŒ์ง€ ๋Œ€๊ธฐํ•œ ํ›„์— ๋‹ค์Œ ๋ฐฐ๋‹ฌ์„ ์ถœ๋ฐœํ•ด์•ผ ํ•œ๋‹ค.

๊ฐ์ฒด ์—ฐ๊ด€ ์„ค๊ณ„

classDiagram
 EventQueue <|-- POS
 PostManager <|-- EventQueue
 PostHub <|-- EventLoop
 EventQueue <|-- PostManager
 PostHub <|-- PostManager
 Postman <|-- PostHub
 EventLoop <|-- PostHub
 PostManager <|-- PostHub
class POS{
	EventQueue eventQueue
	post()
}
class EventQueue{
            Array queue
            PostManager postmanager
            enqueue()
        }
class EventLoop {
	PostHub postHub
	run()
	showState()
}
class PostHub {
	PostMan postman
	EventLoop eventLoop
	PostManager postManager
	boolean isRunning
	Array classifyQueue
	classify()
}

class Postman{
	Array deliverList
	boolean isRunning
	Array delivered
	deliver()
}

class Post{
	number time
	string size
	#getSizeAndTime(size)
}
class PostManager {
	EventQueue eventQueue
	PostHub postHub
	run()
}

์ด๋ ‡๊ฒŒ ์ผ๋‹จ ์„ค๊ณ„๋ฅผ ํ•˜๊ณ  ์‹œ์ž‘ํ•ด๋ณด๋ ค ํ•œ๋‹ค.

๊ฐ์ฒด ๊ตฌํ˜„

POS ํด๋ž˜์Šค

const { EventQueue } = require("./eventQueue");
 
class POS {
  constructor() {
    this.eventQueue = new EventQueue();
  }
  post(size, count) {
    this.eventQueue.enqueue(size, count);
  }
}

POS๊ฐ์ฒด๋Š” ์ฒ˜์Œ ์ฃผ๋ฌธ์„ ๋ฐ›๊ณ  eventQueue๋กœ ํ•ด๋‹น ์ฃผ๋ฌธ์„ ๋„˜๊ฒจ์ค€๋‹ค.

EventQueue ํด๋ž˜์Šค

const { Post } = require("./post");
const { PostManager } = require("./postManager");
 
class EventQueue {
  static instance;
  constructor() {
    if (EventQueue.instance) return EventQueue.instance;
    this.queue = [];
    this.postManager = new PostManager(this);
    EventQueue.instance = this;
  }
  enqueue(size, count) {
    for (let i = 0; i < count; i++) {
      this.queue.push(new Post(size));
    }
    this.postManager.postHub.fullpost += count;
  }
}
 
module.exports = { EventQueue };
 

์ด๋ ‡๊ฒŒ EventQueue ํด๋ž˜์Šค์˜ enqueue ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ํ•ด๋‹น ๋Œ€๊ธฐ ๋ฐฐ์†ก ๋ชฉ๋ก์— ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๊ณ , ์ด๋Ÿฌํ•œ ๋Œ€๊ธฐ ๋ฐฐ์†ก์˜ ๋ชฉ๋ก์˜ ๊ฒฝ์šฐ์—๋Š” PostManagerํด๋ž˜์Šค๊ฐ€ ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ด์ฃผ๋ฉด์„œ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค.

PostManager ํด๋ž˜์Šค

const { Runable } = require("./abstractClass");
const { EventQueue } = require("./eventQueue");
const { PostHub } = require("./postHub");
 
class PostManager extends Runable {
  constructor(eventQueue) {
    super();
    this.eventQueue = eventQueue;
    this.postHub = new PostHub(this);
    this.run();
  }
 
  run() {
    setInterval(() => {
      if (this.eventQueue.queue.length) {
        this.postHub.classifyQueue = this.postHub.classifyQueue.concat([
          ...this.eventQueue.queue,
          "show",
        ]);
        this.eventQueue.queue = [];
      }
    }, 3000);
  }
}
 
module.exports = { PostManager };
 

PostManager ํด๋ž˜์Šค์—์„œ๋Š” run() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ setInterval()์„ ์‹คํ–‰์‹œ์ผœ ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ชฉ๋ก์„ ๋ณด๊ณ  ๋ฌผ๋ฅ˜์ฐฝ๊ณ ์ธ PostHub๋กœ ๋„˜๊ฒจ์ค€๋‹ค.

PostHub ํด๋ž˜์Šค

const { Runable } = require("./abstractClass");
const { EventLoop } = require("./eventLoop");
const { Post } = require("./post");
const { Postman } = require("./postman");
 
class PostHub extends Runable {
  constructor(postManager) {
    super();
    this.postMan = new Postman();
    this.postManager = postManager;
    this.classifyQueue = [];
    this.isRunning = false;
    this.eventLoop = new EventLoop(this);
    this.fullpost = 0;
  }
 
  classify(post) {
    this.isRunning = true;
    console.log(`${post.size} ๋ถ„๋ฅ˜ ์‹œ์ž‘`);
    setTimeout(() => {
      console.log(`${post.size} ๋ถ„๋ฅ˜ ์™„๋ฃŒ`);
      this.postMan.deliverList.push(post);
      this.isRunning = false;
    }, post.time);
  }
}
 
module.exports = { PostHub };
 

์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ง„ PostHub์—์„œ๋Š” eventLoop ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ์‹คํ–‰์‹œํ‚ค๊ฒŒ ๋˜๋Š”๋ฐ, eventLoop๋ฌธ์—์„œ classify๋ฅผ ์‹คํ–‰์‹œ์ผœ ๋ถ„๋ฅ˜๋ฅผ ํ•ด๋‹น ๊ฐ์ฒด ๋‚ด์—์„œ ์ง„ํ–‰ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ๋น„๋™๊ธฐ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด setTimeout์„ ํ†ตํ•ด์„œ ๋ฌผ๋ฅ˜์— ํ•ด๋‹นํ•˜๋Š” ์‹œ๊ฐ„๋งŒํผ, ํ›„์— ์™„๋ฃŒ๋˜๋„๋ก ํ•˜๊ณ , ์ด๋Ÿฌํ•œ ํ•œ ์ž‘์—…์ž์˜ ์ƒํƒœ๋Š” boolean๊ฐ’์œผ๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ํ•ด๋‹น ์ž‘์—…์ž์˜ ์ƒํƒœ๋ฅผ ๋ณด๊ณ  ๋ถ„๋ฅ˜๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค.

EventLoop ํด๋ž˜์Šค

const { Runable } = require("./abstractClass");
 
class EventLoop extends Runable {
  constructor(postHub) {
    super();
    this.postHub = postHub;
    this.run();
  }
 
  async run() {
    const running = setInterval(() => {
      if (!this.postHub.isRunning && this.postHub.classifyQueue.length) {
        const post = this.postHub.classifyQueue.shift();
        if (post === "show") this.showState();
        else this.postHub.classify(post);
      }
      if (
        !this.postHub.postMan.isRunning &&
        this.postHub.postMan.deliverList.length
      ) {
        const deliver = this.postHub.postMan.deliverList.shift();
        this.postHub.postMan.deliver(deliver);
      }
      if (this.postHub.fullpost === this.postHub.postMan.delivered.length) {
        console.log("๋ชจ๋“  ๋ฐฐ์†ก์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
        process.exit();
      }
    }, 1000);
  }
  showState() {
    console.log(
      `๋Œ€๊ธฐ์ค‘:${this.postHub.postManager.eventQueue.queue.join(
        ","
      )}/ ๋ถ„๋ฅ˜์ค‘: ${this.postHub.classifyQueue.join(
        ","
      )}/ ๋ฐฐ์†ก์ค‘:${this.postHub.postMan.deliverList
        .map((item) => item.size)
        .join(",")}/ ๋ฐฐ์†ก์™„๋ฃŒ: ${this.postHub.postMan.delivered
        .map((item) => item.size)
        .join(",")}`
    );
  }
}
 
module.exports = { EventLoop };

EventLoopํด๋ž˜์Šค์—์„œ๋„ ์ฃผ๊ธฐ์ ์œผ๋กœ setInterval์„ ํ†ตํ•ด์„œ ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ฌผ๋ฅ˜ ์„ผํ„ฐ์— ๋‚จ์•„ ์žˆ๋Š” ๋ฌผ๋ฅ˜์™€ ์ž‘์—…์ž์˜ ์ƒํƒœ๋ฅผ ๋ณด๊ณ  ๋ถ„๋ฅ˜๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ๋ฐฐ์†ก์›์˜ ๊ฒฝ์šฐ์—๋„ ๋˜‘๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ฐฐ์†ก์›์˜ ์ƒํƒœ์™€ ๋ฐฐ๋‹ฌ ๋ชฉ๋ก์„ ๋ณด๊ณ  ๋ฐฐ๋‹ฌ์„ ์ฒ˜๋ฆฌํ•ด๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ์‹คํ–‰ํ•˜๋Š” ์กฐ๊ฑด๋ฌธ์„ ๊ฑธ์–ด์ฃผ์—ˆ๋‹ค. ๋งŒ์•ฝ ํ˜„ํ™ฉ์ด ์•ˆ์— ๋“ค์–ด๊ฐ€์žˆ์„ ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ คํ•˜์—ฌ showState๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ•ด๋‹น ๊ฐ์ฒด์— ๋งŒ๋“ค์–ด์ฃผ๊ณ , PostManager๊ฐ€ ๋ณด๋‚ธ show๋ผ๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋”ฐ๋กœ ๊ตฌ๋ณ„ํ•˜์—ฌ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

Postํด๋ž˜์Šค

class Post {
  constructor(size) {
    [this.time, this.size] = this.#getSizeAndTime(size);
  }
  #getSizeAndTime(size) {
    let time;
    let sizeName;
    switch (size) {
      case 1:
        time = 3000;
        sizeName = "์†Œํ˜•";
        break;
      case 2:
        time = 7000;
        sizeName = "์ค‘ํ˜•";
        break;
      case 3:
        time = 15000;
        sizeName = "๋Œ€ํ˜•";
        break;
      default:
        time = 0;
        sizeName = "";
        break;
    }
    return [time, sizeName];
  }
}
 
module.exports = { Post };
 
 

Post ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ ๊ฐ ๋ฐฐ์†ก ๋ฌผ๋ฅ˜์— ๋Œ€ํ•œ ์‚ฌ์ด์ฆˆ๋ฅผ ํ•œ๊ธ€๋กœ ๋ฐ›์•„์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด๋กœ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค.

EventQueue ํด๋ž˜์Šค

class EventQueue {
  static #instance;
  constructor() {
    if (EventQueue.#instance) return EventQueue.#instance;
    this.queue = [];
    this.eventLoop;
  }
  enqueue(size, count) {
    for (let i = 0; i < count; i++) {
      this.queue.push(size);
    }
  }
  dequeue() {}
}
 
module.exports = { EventQueue };
 

EventQueue๋Š” evenloop์™€ ์ข…์†๊ด€๊ณ„์— ์žˆ๋‹ค. ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋˜ํ•œ ์‹ฑ๊ธ€ ํ†ค์œผ๋กœ ๊ตฌํ˜„ํ•˜๋ฉฐ ์ด๋ฅผ EventQueue ๋‚ด์—์„œ eventloop์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ณ„์†ํ•ด์„œ ์‹คํ–‰์‹œํ‚ค๋ฉฐ ๋ฌดํ•œ๋ฃจํ”„๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋ฌธ์ œ 2 ์„ค๊ณ„ํ•˜๊ธฐ

๋ฌธ์ œ 2์—์„œ๋Š” ๋ฌผ๋ฅ˜์„ผํ„ฐ๊ฐ€ 4๊ฐœ๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ๊ทธ ์•ˆ์˜ ๋ฐฐ๋‹ฌ์›๊ณผ ๋ถ„๋ฅ˜์›์„ ์œ ๋™์ ์œผ๋กœ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ EventEmitter์˜ ์ถ”๊ฐ€๋กœ ๋ถ„๋ฅ˜์›/๋ฐฐ์†ก์›/์ž…๋ ฅ ๋“ฑ์˜ ํ–‰์œ„์—์„œ ๊ฐ ์ด๋ฒคํŠธ๋ฅผ ๋‚ด๋ณด๋‚ด์–ด EventEmitter๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๊ณ , Promise์˜ ์‚ฌ์šฉ์œผ๋กœ ๋น„๋™๊ธฐ๋ฅผ ์ง€์›ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋Ÿฐ ๋ชจ์–‘์œผ๋กœ ์„ค๊ณ„ํ•ด๋ดค๋Š”๋ฐ, ์ •๋‹ต. ๋ถ๋‘์น ์„ฑ! ์ด๋Ÿฐ ์‹์˜ ๋น„๋™๊ณ„ ์„ค๊ณ„๋Š” ์ฒ˜์Œ์ด๋ผ ๋„ˆ๋ฌด ๊ณจ์•„ํ”„๋‹ค ๊ณจ์•„ํŒŒ์„œ ๊ณ ๋ผํŒŒ๋•

PostMan ํด๋ž˜์Šค

const { Runable } = require("./abstractClass");
const { emitter } = require("./eventEmitter");
 
class Postman {
  constructor(id, hub) {
    this.delivering = false;
    this.id = id;
    this.hub = hub;
  }
 
  deliver(post) {
    return new Promise((resolve, reject) => {
      emitter.emit("deliverStart", this, post);
      resolve(
        setTimeout(() => {
          emitter.emit("deliverFinish", this, post);
        }, 10000)
      );
    });
  }
}
 
module.exports = { Postman };
 

๊ฐ€์žฅ ํฌ๊ฒŒ ๋ณ€ํ•œ๊ฑด ๋ฐฐ์†ก์›๊ณผ ๋ถ„๋ฅ˜์›์˜ ๋กœ์ง์ด๋‹ค. ๋ฐฐ์†ก์›/๋ถ„๋ฅ˜์›์˜ ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ๋ช…์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ ์ธ์›์— ๋Œ€ํ•ด์„œ ๋ฐฐ์—ด๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•  ํ•„์š”์„ฑ์„ ๋А๊ผˆ๋‹ค. ๋˜ํ•œ Promise๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ–ˆ๋Š”๋ฐ, ์ด์ œ๊นŒ์ง€๋Š” settimeout์˜ ์ฝœ๋ฐฑ์— resolve๋ฅผ ๋‘๊ณ  ํ•œ์ฐธ ๊ณ ๋ฏผํ–ˆ๋Š”๋ฐ ์ƒ๊ฐํ•ด๋ณด๋‹ˆ ๋ฐ–์œผ๋กœ ๋บ€ ๋‹ค์Œ์— ํ•ด๋‹น ์ง์›๋“ค์˜ ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ์†์„ฑ์„ ๋‘๊ณ  ๋”ฐ๋กœ ๊ด€๋ฆฌํ•˜๋ฉด ๋๋‹ค. ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์€ emitter๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌํ•ด์ฃผ์—ˆ๋‹ค.

Hubworker ํด๋ž˜์Šค

const { emitter } = require("./eventEmitter");
 
class HubWorker {
  constructor(hub, id) {
    this.id = id;
    this.working = false;
    this.hub = hub;
  }
  classify(post1, post2) {
    let time = post1.time;
    if (post2) {
      time = post1.time > post2.time ? post1.time : post2.time;
    }
    emitter.emit("classifyStart", this, post1, post2);
    return new Promise((resolve, reject) => {
      resolve(
        setTimeout(() => {
          emitter.emit("classified", this, post1, post2);
        }, time)
      );
    });
  }
}
 
module.exports = { HubWorker };
 

๊ฐ ๋ถ„๋ฅ˜์›๋„ ์ธ์›๋งˆ๋‹ค ๊ด€๋ฆฌ๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํŠน์ดํ•œ ์ ์€ ํ•œ ์ง์›๋‹น ๋‘ ๊ฐœ์˜ ํƒ๋ฐฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•œ๊ฐœ๋งŒ ๋‚จ์•˜์„ ๊ฒฝ์šฐ๋‚˜ ๋‘ ๊ฐœ์˜ ํƒ๋ฐฐ๊ฐ€ ๋“ค์–ด์˜ฌ ๊ฒฝ์šฐ๋ฅผ ์กฐ๊ฑด๋ฌธ์„ ํ†ตํ•ด ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ์—ˆ๋‹ค.

EventLoop ํด๋ž˜์Šค

const { Runable } = require("./abstractClass");
 
class EventLoop extends Runable {
  constructor(postHub) {
    super();
    this.postHub = postHub;
    this.run();
  }
 
  async run() {
    const running = setInterval(() => {
      this.#letsWorkHub();
      this.#letsWorkPostman();
    }, 1000);
  }
 
  #letsWorkHub() {
    while (this.postHub.classifyQueue.length) {
      let addedWork;
      if (this.postHub.classifyQueue.length >= 2) {
        addedWork = this.postHub.classifyQueue.shift();
      }
      const worker = this.#findHubWorker();
      if (worker)
        worker.classify(this.postHub.classifyQueue.shift(), addedWork);
      else return;
    }
  }
  #letsWorkPostman() {
    while (this.postHub.postToDeliver.length) {
      const postman = this.#findPostMan();
      if (postman) postman.deliver(this.postHub.postToDeliver.shift());
      else return;
    }
  }
 
  #findHubWorker() {
    for (const worker of this.postHub.hubWorker) {
      if (!worker.working) return worker;
    }
    return false;
  }
  #findPostMan() {
    for (const worker of this.postHub.postMan) {
      if (!worker.delivering) return worker;
    }
    return false;
  }
  showState() {}
}
 
module.exports = { EventLoop };
 

EventLooP๋Š” ๊ธฐ์กด๊ณผ๋Š” ๋น„์Šทํ•œ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•˜์ง€๋งŒ, ์—ฌ๊ธฐ์„œ ์ถ”๊ฐ€๋œ ์ ์€ ์—ฌ๋Ÿฌ ๋ช…์˜ ์ง์›๋“ค์ด ์žˆ์„ ๊ฒฝ์šฐ์— ๊ฐ€๋Šฅํ•œ ์ง์›์„ ๋ฝ‘์•„ ํ•ด๋‹นํ•˜๋Š” ์ผ์„ ๋งก๊ฒจ์•ผ ํ–ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์„ ๊ณ ๋ คํ•ด์„œ Property์— ์ถ”๊ฐ€ํ•ด๋†“์€ ์ƒํƒœ boolean ๊ฐ’์„ ํ™œ์šฉํ•˜์—ฌ ํ˜„์žฌ ์ผํ•˜๊ณ  ์žˆ์ง€ ์•Š์€ ์ง์›์„ ์ฐพ์•„ ํ•ด๋‹น ์ง์›์—๊ฒŒ ์ผ์„ ํ• ๋‹นํ•˜๋„๋ก ํ–ˆ๋‹ค.

Posthub ํด๋ž˜์Šค

const { emitter } = require("./eventEmitter");
const { EventLoop } = require("./eventLoop");
const { HubWorker } = require("./hubWorker");
const { Post } = require("./post");
const { Postman } = require("./postman");
 
class PostHub {
  constructor(postManager, hubWorker, postMen, id) {
    this.postMan = Array.from(
      { length: postMen },
      (_, idx) => new Postman(idx, this)
    );
    this.postToDeliver = [];
    this.postManager = postManager;
    this.hubWorker = Array.from(
      { length: hubWorker },
      (_, idx) => new HubWorker(this, idx)
    );
    this.classifyQueue = [];
    this.eventLoop = new EventLoop(this);
    this.id = id;
  }
}
 
module.exports = { PostHub };
 

๊ธฐ์กด์—๋Š” PostHub ํด๋ž˜์Šค ์•ˆ์— ๋ถ„๋ฅ˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋†“์•˜์ง€๋งŒ, ์ด๋ฅผ ๋”ฐ๋กœ Hubworker ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋“ค์˜ ๋ฉ”์„œ๋“œ๋กœ ๋“ค์–ด๊ฐ€๋ฉด์„œ ํ•ด๋‹น ๋ฌผ๋ฅ˜์„ผํ„ฐ์—์„œ ํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๋”ฐ๋กœ ํ•„์š”์—†๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ ๋ชจ์กฐ๋ฆฌ ๋นผ๋ฒ„๋ ธ๋‹ค.

EventEmitter ํด๋ž˜์Šค

const EventEmmiter = require("events");
class PostEventEmmiter extends EventEmmiter {}
 
const emitter = new PostEventEmmiter();
emitter.on("recept", (postManager, count) => {
  postManager.sendToHub();
  postManager.fullPosts += count;
});
 
emitter.on("classifyStart", (worker, post1, post2) => {
  console.log(
    `๋ฌผ๋ฅ˜์„ผํ„ฐ${worker.hub.id}์˜ ์ž‘์—…์ž${worker.id}-${post1.sender}${post1.size} ๋ถ„๋ฅ˜์‹œ์ž‘`
  );
  if (post2)
    console.log(
      `๋ฌผ๋ฅ˜์„ผํ„ฐ${worker.hub.id}์˜ ์ž‘์—…์ž${worker.id}-${post2.sender}${post2.size} ๋ถ„๋ฅ˜์‹œ์ž‘`
    );
  worker.working = true;
});
emitter.on("classified", (worker, post1, post2) => {
  console.log(
    `๋ฌผ๋ฅ˜์„ผํ„ฐ${worker.hub.id}์˜ ์ž‘์—…์ž${worker.id}-${post1.sender}${post1.size} ๋ถ„๋ฅ˜์ข…๋ฃŒ`
  );
  if (post2)
    console.log(
      `๋ฌผ๋ฅ˜์„ผํ„ฐ${worker.hub.id}์˜ ์ž‘์—…์ž${worker.id}-${post2.sender}${post2.size} ๋ถ„๋ฅ˜์ข…๋ฃŒ`
    );
  worker.hub.postToDeliver.push(post1);
  if (post2) worker.hub.postToDeliver.push(post2);
  worker.working = false;
});
 
emitter.on("deliverStart", (postMan, post) => {
  postMan.delivering = true;
  console.log(
    `๋ฌผ๋ฅ˜์„ผํ„ฐ${postMan.hub.id}์˜ ๋ฐฐ๋‹ฌ๊ธฐ์‚ฌ${postMan.id}-๊ณ ๊ฐ${post.sender}${post.size}๋ฐฐ๋‹ฌ์‹œ์ž‘`
  );
});
emitter.on("deliverFinish", (postMan, post) => {
  postMan.delivering = false;
  console.log(
    `๋ฌผ๋ฅ˜์„ผํ„ฐ${postMan.hub.id}์˜ ๋ฐฐ๋‹ฌ๊ธฐ์‚ฌ${postMan.id}-๊ณ ๊ฐ${post.sender}${post.size}๋ฐฐ๋‹ฌ์™„๋ฃŒ`
  );
  postMan.hub.postManager.delivered++;
  console.log(
    postMan.hub.postManager.delivered,
    postMan.hub.postManager.fullPosts
  );
  if (postMan.hub.postManager.delivered === postMan.hub.postManager.fullPosts) {
    console.log("๋ชจ๋“  ๋ฌผํ’ˆ์ด ๋ฐฐ๋‹ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    process.exit();
  }
});
 
module.exports = { emitter };
 

EventEmitter์˜ ๊ฒฝ์šฐ์—๋Š” ๊ทธ๋ƒฅ ์ƒ์†์„ ํ†ตํ•ด ๊ธฐ์กด ์ด๋ฒคํŠธ์—๋ฏธํ„ฐ๋ฅผ ์ƒ์†๋ฐ›๊ณ , ๋‚ด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“  ๋‹ค์Œ ํ•ด๋‹นํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋ชจ์กฐ๋ฆฌ ํ•œ ๊ณณ์—์„œ ๋“ฑ๋ก์‹œ์ผœ์ฃผ๊ณ  ์‚ฌ์šฉํ–ˆ๋‹ค. ์š”๊ตฌ์‚ฌํ•ญ์— ๋‚˜์™€์žˆ๋Š”๋Œ€๋กœ ๊ฐ ์ž‘์—…์ด ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜ ๋๋‚  ๋•Œ๋งˆ๋‹ค์˜ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ๊ฐ ๋“ฑ๋กํ•ด์ฃผ์–ด ํ•ด๋‹นํ•˜๋Š” ์ง์›์˜ํ™œ๋™ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์ฝ˜์†”๋กœ ์ฐ๋Š” ๋กœ์ง๋“ค๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค,. ๋‚˜๋Š” ์—ฌ๊ธฐ์„œ ์ข…๋ฃŒ ์กฐ๊ฑด์„ ๊ฑธ์—ˆ๋Š”๋ฐ, EventEmitter๊ฐ€ ๋ฐฐ๋‹ฌ์ด ์™„๋ฃŒ๋์„ ๋•Œ์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์•ผ ํ•œ๋Œ€์„œ ์™œ ๊ทธ๋Ÿด๊นŒ ์ƒ๊ฐ์„ ํ•ด๋ดค๋Š”๋ฐ ์ด์ œ๊นŒ์ง€ ๋ฐฐ๋‹ฌํ•œ ํšŸ์ˆ˜์™€ ์ฒ˜์Œ์— ๋ฐ›์•˜๋˜ ๋ชจ๋“  ํƒ๋ฐฐ๋“ค์˜ ์ˆ˜๋ฅผ ๋”ฐ๋กœ postManager์—์„œ ๊ด€๋ฆฌํ•˜์—ฌ ์ค€๋‹ค๋ฉด ์ข…๋ฃŒ ์กฐ๊ฑด์„ ๋”ฐ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ์ด์— ์—ฌ๊ธฐ์„œ ๋ฐฐ๋‹ฌ์ด ์™„๋ฃŒ๋  ๋•Œ๋งˆ๋‹ค ํ˜„ํ™ฉ์„ ๊ฐฑ์‹ ํ•˜์—ฌ ๋ฐฐ๋‹ฌํ•œ ๋ฌผํ’ˆ ๊ฐœ์ˆ˜์™€ ์ด ๊ฐœ์ˆ˜๊ฐ€ ๊ฐ™์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•˜๋„๋ก ํ–ˆ๋‹ค.

PostManager ํด๋ž˜์Šค

const { emitter } = require("./eventEmitter");
const { PostHub } = require("./postHub");
 
class PostManager {
  constructor(eventQueue, hubWorker, postMen) {
    this.eventQueue = eventQueue;
    this.postHub = Array.from(
      { length: 4 },
      (_, idx) => new PostHub(this, hubWorker, postMen, idx)
    );
    this.fullPosts = 0;
    this.delivered = 0;
  }
 
  sendToHub() {
    if (this.eventQueue.queue.length) {
      this.postHub.sort(
        (hub1, hub2) => hub1.classifyQueue.length - hub2.classifyQueue.length
      );
      this.postHub[0].classifyQueue = this.postHub[0].classifyQueue.concat(
        this.eventQueue.queue
      );
      this.eventQueue.queue = [];
    }
  }
}
 
module.exports = { PostManager };
 

๊ธฐ์กด PostManager์€ ์—ฌ๊ธฐ์„œ setInterval์„ ํ†ตํ•ด ์ฃผ๊ธฐ์ ์œผ๋กœ ํ์— ์žˆ๋Š” pos์˜ ์š”์ฒญ๋“ค์„ ๊ฐ€์ ธ์™”๋‹ค๋ฉด, ์—ฌ๊ธฐ์„œ๋Š” sendToHub๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋กœ ๋ฐ”๊ฟ” eventemitter๋ฅผ ํ†ตํ•ด์„œ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค.

๊ฒฐ๊ณผ

ํ•™์Šต๋ฉ”๋ชจ

https://luxurious-share-af6.notion.site/Day11-f2a66dd0e7ef45c8bea1e157e37a0998?pvs=4 ์ž์„ธํ•œ ๊ฒƒ์€ ํ•™์Šต ๋ฉ”๋ชจ๋ฅผ,,,

๊ฐœ์„ 

๊ตฌ์กฐ์  ์ธก๋ฉด

  • Runable ์ƒ์† ๋นผ๊ธฐ โœ… 2024-07-30
  • Emitter๋ฅผ ํด๋ž˜์Šค๋งˆ๋‹ค ์ƒ์† โœ… 2024-07-30
  • ๋ฉ”์„œ๋“œ๊ฐ€ ์•„๋‹Œ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง โœ… 2024-07-30
  • ๋ฐฐ์†ก์›๋งˆ๋‹ค ์ „๋‹ดํ•˜๋Š” ํ’ˆ๋ชฉ ์„ค์ • โœ… 2024-07-30
  • dashboard ํด๋ž˜์Šค ๋งŒ๋“ค์–ด์„œ ํ˜„ํ™ฉ ๊ด€๋ฆฌ โœ… 2024-07-30
  • main splitํ•ด์„œ ๋ฐ›๋Š” ์ž…๋ ฅ ๋ถ€๋ถ„ ์ •๊ทœํ‘œํ˜„์‹์œผ๋กœ ๋ฐ”๊พธ๊ธฐ
  • ์—ฌ๋Ÿฌ๊ฐœ ์ž…๋ ฅ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
  • ์ž…๋ ฅํ•œ ํ›„์— ๋ฌผ๋ฅ˜์„ผํ„ฐ๋‚˜ ๋ฐฐ์†ก ์ฒ˜๋ฆฌ ์ค‘์—๋„ ๋‹ค์‹œ ์ž…๋ ฅ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ๋” ์„ค์ •

๊ธฐ๋Šฅ์  ์ธก๋ฉด

  • ์ž‘์—…์ž๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ
  • POS ์—ฌ๋Ÿฌ๊ฐœ ๋‘๊ธฐ
  • ๋ฐฐ์†ก๊ธฐ์‚ฌ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋ฌผํ’ˆ ๋ฐฐ์†กํ•˜๊ธฐ

๋น„๊ธฐ๋Šฅ์  ์ธก๋ฉด

  • ๋‹จ์œ„ํ…Œ์ŠคํŠธ ์‹คํ–‰ํ•˜๊ธฐ
  • ํ…Œ์ŠคํŠธ ๋ณด๊ฐ•ํ•˜๊ธฐ

๊ธฐํƒ€

  • package-lock.json gitignore ์ฒ˜๋ฆฌ โœ… 2024-07-30

๊ตฌ์กฐ์  ์ธก๋ฉด ๊ฐœ์„ 

1. Runable ์ƒ์† ์ œ๊ฑฐ

์ถ”์ƒ ํด๋ž˜์Šค์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์†๋ฐ›์•˜๋˜ Runable์„ ์‚ญ์ œํ–ˆ๋‹ค. ์›๋ž˜์˜ ๊ฒฝ์šฐ๋ผ๋ฉด run ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„ ํด๋ž˜์Šค๋“ค์—๊ฒŒ ์ƒ์†์‹œ์ผœ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜๋Š” ๋ฐฉ์‹์˜ ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„๋ฅผ ๋งŽ์ด ๋ณด์•„์„œ ๋”ฐ๋ผํ•˜๋ คํ–ˆ๋Š”๋ฐ ์˜ˆ์ƒ๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ ์ฝ”๋“œ๋ฅผ ๋ด๋„ ๋”ฑํžˆ ํ•„์š”๊ฐ€ ์—†์–ด ๋ณด์ด๋Š” ์ถ”์ƒํด๋ž˜์Šค๊ฐ™์•„ ์‚ญ์ œํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

2. Emitter๋ฅผ ํด๋ž˜์Šค๋งˆ๋‹ค ์ƒ์†

const EventEmmiter = require("events");
class PostEventEmmiter extends EventEmmiter {}
 
const emitter = new PostEventEmmiter();
emitter.on("recept", (postManager, count) => {
  postManager.sendToHub();
  postManager.fullPosts += count;
});
 
emitter.on("classifyStart", (worker, post1, post2) => {
  console.log(
    `๋ฌผ๋ฅ˜์„ผํ„ฐ${worker.hub.id}์˜ ์ž‘์—…์ž${worker.id}-${post1.sender}${post1.size} ๋ถ„๋ฅ˜์‹œ์ž‘`
  );
  if (post2)
    console.log(
      `๋ฌผ๋ฅ˜์„ผํ„ฐ${worker.hub.id}์˜ ์ž‘์—…์ž${worker.id}-${post2.sender}${post2.size} ๋ถ„๋ฅ˜์‹œ์ž‘`
    );
  worker.working = true;
});
emitter.on("classified", (worker, post1, post2) => {
  console.log(
    `๋ฌผ๋ฅ˜์„ผํ„ฐ${worker.hub.id}์˜ ์ž‘์—…์ž${worker.id}-${post1.sender}${post1.size} ๋ถ„๋ฅ˜์ข…๋ฃŒ`
  );
  if (post2)
    console.log(
      `๋ฌผ๋ฅ˜์„ผํ„ฐ${worker.hub.id}์˜ ์ž‘์—…์ž${worker.id}-${post2.sender}${post2.size} ๋ถ„๋ฅ˜์ข…๋ฃŒ`
    );
  worker.hub.postToDeliver.push(post1);
  if (post2) worker.hub.postToDeliver.push(post2);
  worker.working = false;
});
 
emitter.on("deliverStart", (postMan, post) => {
  postMan.delivering = true;
  console.log(
    `๋ฌผ๋ฅ˜์„ผํ„ฐ${postMan.hub.id}์˜ ๋ฐฐ๋‹ฌ๊ธฐ์‚ฌ${postMan.id}-๊ณ ๊ฐ${post.sender}${post.size}๋ฐฐ๋‹ฌ์‹œ์ž‘`
  );
});
emitter.on("deliverFinish", (postMan, post) => {
  postMan.delivering = false;
  console.log(
    `๋ฌผ๋ฅ˜์„ผํ„ฐ${postMan.hub.id}์˜ ๋ฐฐ๋‹ฌ๊ธฐ์‚ฌ${postMan.id}-๊ณ ๊ฐ${post.sender}${post.size}๋ฐฐ๋‹ฌ์™„๋ฃŒ`
  );
  postMan.hub.postManager.delivered++;
  console.log(
    postMan.hub.postManager.delivered,
    postMan.hub.postManager.fullPosts
  );
  if (postMan.hub.postManager.delivered === postMan.hub.postManager.fullPosts) {
    console.log("๋ชจ๋“  ๋ฌผํ’ˆ์ด ๋ฐฐ๋‹ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    process.exit();
  }
});
 
module.exports = { emitter };

๊ธฐ์กด EventEmitter์˜ ๊ฒฝ์šฐ ํ•˜๋‚˜์˜ emitter ์ธ์Šคํ„ด์Šค๋ฅผ ๋„ฃ์–ด๋†“๊ณ , ๊ฐ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋ชจ๋‘ ์•ˆ์— ๋•Œ๋ ค๋„ฃ๋Š” ๋ฌด์‹ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์—ˆ๋‹ค. ์ž‘์„ฑํ•˜๊ณ  ๋ณด๋‹ˆ ์ด๋ฒคํŠธ๋ช… ๋ง๊ณ ๋Š” ์ œ๋Œ€๋กœ ํŒ๋‹จ์ด ์•ˆ ๋˜๋Š” ์ด๋ฒคํŠธ๋“ค์ด ๋‚œ๋ฌดํ•˜์—ฌ ์ด๋ฅผ ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ๊ฒƒ์ด ์šฐ์„ ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

const { DashBoard } = require("./dashboard");
const { EventLoop } = require("./eventLoop");
const { HubWorker } = require("./hubWorker");
const { Postman } = require("./postman");
const EventEmitter = require("events");
 
class PostHub extends EventEmitter {
  constructor(postManager, hubWorker, postMen, id) {
    super();
    this.postMan = Array.from(
      { length: postMen },
      (_, idx) => new Postman(idx, this)
    );
    this.postToDeliver = [];
    this.postManager = postManager;
    this.dashBoard = new DashBoard();
    this.hubWorker = Array.from(
      { length: hubWorker },
      (_, idx) => new HubWorker(this, idx)
    );
    this.classifyQueue = [];
    this.eventLoop = new EventLoop(this);
    this.id = id;
    this.on("letsWork", this.letsWork);
  }
 
  letsWork() {
    while (this.classifyQueue.length) {
      const [work1, work2] = this.#findPostToClassify();
      this.#findWorker().emit("letsClassify", work1, work2);
    }
    while (this.postToDeliver.length) {
      const postman = this.#findPostMan(this.postToDeliver[0].sizeNum);
      if (!postman) break;
      postman.emit("letsDeliver", this.postToDeliver.shift());
    }
  }
  #findWorker() {
    return this.hubWorker.find((worker) => !worker.working);
  }
  #findPostMan(postSize) {
    const foundPostMan = this.postMan.find(
      (postman) => postman.id % 4 === postSize % 4
    );
    if (!foundPostMan)
      return this.postMan.find((postman) => !postman.delivering);
    return foundPostMan;
  }
  #findPostToClassify() {
    if (this.classifyQueue.length) {
      let work = this.classifyQueue.shift();
      let addedWork;
      if (this.classifyQueue.length >= 2) {
        addedWork = this.classifyQueue.shift();
      }
      return [work, addedWork];
    }
  }
}
 
module.exports = { PostHub };
 

๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ๋ฌผ๋ฅ˜์„ผํ„ฐ ํด๋ž˜์Šค๋ฅผ ๋ณด์ž. EventEmitter๋ฅผ ์ƒ์†ํ•ด์„œ ์•ˆ์—์„œ ์„ ์–ธํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง์„ ์ง„ํ–‰ํ–ˆ๊ณ , ์ด๋Ÿฌํ•œ ์ด๋ฒคํŠธ์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” ๋ฉ”์„œ๋“œ๋กœ ์ •์˜ํ•˜์—ฌ ๋ณด๋‹ค ์–ด๋–ค ๊ฐ์ฒด ์•ˆ์—์„œ ์–ด๋–ค ์ด๋ฒคํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š”์ง€์— ๋Œ€ํ•ด์„œ ๋ช…ํ™•ํ•ด์ง„ ๋А๋‚Œ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

3. ๋ฉ”์„œ๋“œ๊ฐ€ ์•„๋‹Œ ์ด๋ฒคํŠธ ์ „๋‹ฌ ๋ฐฉ์‹์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง

class EventLoop {
  constructor(postHub) {
    this.postHub = postHub;
    this.run();
  }
 
  async run() {
    const running = setInterval(() => {
      this.postHub.emit("letsWork");
    }, 1000);
  }
}
 
module.exports = { EventLoop };

๋ฌผ๋ฅ˜์„ผํ„ฐ ํด๋ž˜์Šค์—์„œ ์„ ์–ธํ•œ ์ด๋ฒคํŠธ๋ฅผ ํ™œ์š”์•Ÿ๊ธฐ ์œ„ํ•ด ์ด๋ฒคํŠธ๋ฃจํ”„์˜ ๊ตฌ์กฐ๋ฅผ ๋Œ€ํญ ๋ณ€๊ฒฝํ–ˆ๋‹ค. ์ด์ œ๋Š” setInterval์„ ํ†ตํ•ด ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ฐฐ์†ก๊ณผ ๋ถ„๋ฅ˜ ์—…๋ฌด๋ฅผ ํ•˜๋„๋ก ํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์†กํ•˜๊ณ , ํ•ด๋‹น ์ด๋ฒคํŠธ๋Š” ์ƒ์œ„ ๊ฐ์ฒด์ธ ๋ฌผ๋ฅ˜์„ผํ„ฐ ๊ฐ์ฒด์—์„œ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•จ์œผ๋กœ์จ ๋ณด๋‹ค ๋ฐ์ดํ„ฐ์˜ ์ œ์–ด ํ๋ฆ„์„ ์šฉ์ดํ•˜๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

4. ๋ฐฐ์†ก์›๋งˆ๋‹ค ์ „๋‹ดํ•˜๋Š” ํ’ˆ๋ชฉ ์ง€์ •

  letsWork() {
    while (this.classifyQueue.length) {
      const [work1, work2] = this.#findPostToClassify();
      this.#findWorker().emit("letsClassify", work1, work2);
    }
    while (this.postToDeliver.length) {
      const postman = this.#findPostMan(this.postToDeliver[0].sizeNum);
      if (!postman) break;
      postman.emit("letsDeliver", this.postToDeliver.shift());
    }
  }
  #findWorker() {
    return this.hubWorker.find((worker) => !worker.working);
  }
  #findPostMan(postSize) {
    const foundPostMan = this.postMan.find(
      (postman) => postman.id % 4 === postSize % 4
    );
    if (!foundPostMan)
      return this.postMan.find((postman) => !postman.delivering);
    return foundPostMan;
  }

๋„ˆ๋ฌด ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์—ˆ๋˜ ๋ฐฐ์†ก์›๋งˆ๋‹ค ์ „๋‹ดํ•˜๋Š” ํ’ˆ๋ชฉ ๋˜ํ•œ ๋ฆฌํŒฉํ† ๋ง์„ ํ†ตํ•ด ํ•จ๊ป˜ ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ๋ฐฐ์†ก์›๋งˆ๋‹ค ์ „๋‹ดํ•˜๋Š” ํ’ˆ๋ชฉ์„ ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€?๋ฅผ ์ƒ๊ฐํ•˜๋‹ค๊ฐ€ ๊ฐ ๋ฐฐ์†ก์›์—๊ฒŒ id๊ฐ’์œผ๋กœ ์ฒ˜์Œ์— ๋ฐฐ์—ด์— ๋„ฃ์–ด์ค„ ๋•Œ ์ธ๋ฑ์Šค๊ฐ’์„ ๋„ฃ์–ด์ค€ ๊ฒƒ์ด ์ƒ๊ฐ๋‚ฌ๋‹ค.

์ด๋ฅผ ํ™œ์šฉํ•ด์„œ 14๊นŒ์ง€ ์žˆ๋Š” ์‚ฌ์ด์ฆˆ์—์„œ ํ•˜๋‚˜๋ฅผ ์ „๋‹ด์œผ๋กœ ์„ ํƒํ–ˆ์–ด์•ผ ํ–ˆ๋Š”๋ฐ, 4๋กœ ๋‚˜๋ˆˆ ๋‚˜๋จธ์ง€๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์ธ๋ฑ์Šค๊ฐ’์ด ์•„๋ฌด๋ฆฌ ๋Š˜์–ด๋‚˜๋„ 03๊นŒ์ง€๋งŒ ์žˆ์„ ๊ฒƒ์ด๊ณ , ์‚ฌ์ด์ฆˆ์˜ ๊ฒฝ์šฐ๋„ 0~3๋งŒ์„ ์™”๋‹ค๊ฐ”๋‹ค ํ•  ๊ฒƒ์ด๋‹ค.

์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ find ๊ณ ์ฐจํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•ด์„œ ์ „๋‹ดํ•˜๋Š” ์‚ฌ์ด์ฆˆ์˜ ๋ฐฐ์†ก์›์—๊ฒŒ ๋ณด๋‹ค ์šฐ์„ ์ ์œผ๋กœ ๋ฐฐ์ •ํ•ด์ฃผ๋ ค ํ•˜์˜€์œผ๋ฉฐ, ์ถ”๊ฐ€์ ์œผ๋กœ ๋งŒ์•ฝ ์ „๋‹ดํ•˜๋Š” ๋ฐฐ์†ก์›์ด ์—†๋‹ค ํ•˜๋”๋ผ๋„ ๋‚จ์•„์„œ ์‰ฌ๊ณ  ์žˆ๋Š” ๋ฐฐ์†ก์›์—๊ฒŒ ํ›„์ˆœ์œ„๋กœ ๋ฐฐ์ •ํ•ด์ฃผ๋ ค๊ณ  ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ์Šค์ผ€์ค„๋ง์„ ์„ค๊ณ„ํ–ˆ๋‹ค.

5. Dashboard ํด๋ž˜์Šค ๋งŒ๋“ค์–ด์„œ ํ˜„ํ™ฉ ๊ด€๋ฆฌ

const EventEmitter = require("events");
class DashBoard extends EventEmitter {
  static instance;
  constructor() {
    super();
    if (DashBoard.instance) return DashBoard.instance;
    this.isPending = [];
    this.isClassifing = [];
    this.isWaitingDeliver = [];
    this.isDelivering = [];
    this.isDelivered = [];
    DashBoard.instance = this;
    this.on("addPending", this.addPending);
    this.on("addClassifying", this.addClassifying);
    this.on("addWaiting", this.addWaitingDeliver);
    this.on("addDelivering", this.addDelivering);
    this.on("addDelivered", this.addDelivered);
  }
  stringify(postArr) {
    return postArr
      .map((post) => `${post.sender}๋‹˜์˜ ${post.size}๋ฌผํ’ˆ`)
      .join(",");
  }
  showState() {
    console.log("----------------------------------");
    console.log(
      `๋ถ„๋ฅ˜๋Œ€๊ธฐ-${this.stringify(this.isPending)}\n๋ถ„๋ฅ˜์ค‘-${this.stringify(
        this.isClassifing
      )}\n๋ฐฐ๋‹ฌ๋Œ€๊ธฐ-${this.stringify(
        this.isWaitingDeliver
      )}\n๋ฐฐ๋‹ฌ์ค‘-${this.stringify(
        this.isDelivering
      )}\n๋ฐฐ๋‹ฌ์™„๋ฃŒ-${this.stringify(this.isDelivered)}/`
    );
    console.log("----------------------------------");
  }
  addPending(post) {
    this.isPending.push(post);
    this.showState();
  }
  deletePending(targetPost) {
    this.isPending = this.isPending.filter((post) => post != targetPost);
  }
  addClassifying(post) {
    this.deletePending(post);
    this.isClassifing.push(post);
    this.showState();
  }
  deleteClassifying(targetPost) {
    this.isClassifing = this.isClassifing.filter((post) => post !== targetPost);
  }
  addWaitingDeliver(post) {
    this.deleteClassifying(post);
    this.isWaitingDeliver.push(post);
    this.showState();
  }
  deleteWaiting(targetPost) {
    this.isWaitingDeliver = this.isWaitingDeliver.filter(
      (post) => post !== targetPost
    );
  }
  addDelivering(post) {
    this.deleteWaiting(post);
    this.isDelivering.push(post);
    this.showState();
  }
  addDelivered(targetPost) {
    this.isDelivering = this.isDelivering.filter((post) => post !== targetPost);
    this.isDelivered.push(targetPost);
    this.showState();
  }
}
 
module.exports = { DashBoard };
 

๋ง‰์ƒ ์ „์— ๋‹ค ๋งŒ๋“ค๊ณ  ๋ณด๋‹ˆ ํ˜„ํ™ฉ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”๊ฑธ ๊นœ๋นกํ–ˆ์—ˆ๋‹ค. ์ด ๋˜ํ•œ ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ค์šด ๊ฒƒ์€ ์•„๋‹ˆ๋‹ˆ ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.

dashboard ํด๋ž˜์Šค ๋˜ํ•œ EventEmitter๋ฅผ ์ƒ์†ํ•ด์„œ ํ•ด๋‹น ํด๋ž˜์Šค ๊ฐ์ฒด ์•ˆ์—์„œ ์ด๋ฒคํŠธ๋ฅผ ์„ ์–ธํ•ด์ฃผ๊ณ , ๋‹ค๋ฅธ ๊ณณ์—์„œ๋Š” ์ด ํด๋ž˜์Šค์— ์ง„์ž…ํ•˜์—ฌ ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰ํ•จ์œผ๋กœ์จ ๊ฐ Post๊ฐ์ฒด์— ๋Œ€ํ•˜์—ฌ ๋ถ„๋ฅ˜๋Œ€๊ธฐ,๋ถ„๋ฅ˜์ค‘,๋ฐฐ๋‹ฌ๋Œ€๊ธฐ,๋ฐฐ๋‹ฌ์ค‘,๋ฐฐ๋‹ฌ์™„๋ฃŒ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๊ณ , ๋‚˜์ค‘์—๋Š” ์ด๋Ÿฌํ•œ ๋ฐฐ์—ด์„ ํ™œ์šฉํ•ด์„œ ํ˜„ํ™ฉ์„ ํ‘œ์‹œํ•ด์•ผ ํ•˜๊ธฐ ๋–„๋ฌธ์— stringify๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์–ด ๋ฌธ์ž์—ด๋กœ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

์ด๋Ÿฌํ•œ dashBoard์˜ ๊ฒฝ์šฐ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ด๋–ค ๊ฐ์ฒด์— ์žˆ๋“ ์ง€ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•จ์œผ๋กœ์จ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฌผ๋ฅ˜์„ผํ„ฐ๊ฐ€ ๋‚˜๋ˆ ์ง€๋Š” ๊ฒฝ์šฐ์—๋„ ๊ฐ ๋ฐฐ์†ก์›, ๋ฌผ๋ฅ˜์› ๋“ฑ์ด ํ™œ๋™ํ•  ๋•Œ๋งˆ๋‹ค ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰์‹œ์ผœ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ํ˜„ํ™ฉ์„ ์ตœ์‹ ํ™”ํ•˜๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.