国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

構(gòu)建 NodeJS 影院預(yù)訂微服務(wù)并使用 docker 部署(03/4)

這篇具有很好參考價值的文章主要介紹了構(gòu)建 NodeJS 影院預(yù)訂微服務(wù)并使用 docker 部署(03/4)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、說明

????????構(gòu)建一個微服務(wù)的電影網(wǎng)站,需要Docker、NodeJS、MongoDB,這樣的案例您見過嗎?如果對此有興趣,您就繼續(xù)往下看吧。

構(gòu)建 NodeJS 影院預(yù)訂微服務(wù)并使用 docker 部署(03/4),docker,微服務(wù),docker,架構(gòu)

你好社區(qū),這是??“構(gòu)建 NodeJS 影院微服務(wù)”系列的第三篇文章。本系列文章演示了如何使用 ES6、?ES7 ...8?,連接到 MongoDB 副本集,本文還演示了如何將其部署到 docker 容器中,并模擬此微服務(wù)在云環(huán)境中的運行方式。

二、我們前幾章的快速回顧

  • 我們談?wù)撌裁词俏⒎?wù),我們看到了微服務(wù)的優(yōu)點和缺點
  • 我們定義了影院微服務(wù)架構(gòu)。
  • 我們設(shè)計和開發(fā)了電影服務(wù)和電影目錄服務(wù)。
  • 我們?yōu)槊總€服務(wù)制作了一個API,并對我們的API進行了單元測試
  • 我們編寫我們的 API 以使其成為服務(wù)并將其運行到?Docker?容器中。
  • 我們對在?Docker?上運行的服務(wù)進行了集成測試。
  • 我們談?wù)?strong>微服務(wù)安全性,我們實現(xiàn)HTTP / 2協(xié)議。
  • 我們對電影目錄服務(wù)進行了壓力測試。

????????如果你還沒有讀過前面的章節(jié),你錯過了一些有趣的東西????,我會把鏈接放在下面,所以你可以看看??。

????????在前面的章節(jié)中,我們已經(jīng)實現(xiàn)了下圖中的高級子體系結(jié)構(gòu),我們將在本章中開始開發(fā)較差的子體系結(jié)構(gòu)。

構(gòu)建 NodeJS 影院預(yù)訂微服務(wù)并使用 docker 部署(03/4),docker,微服務(wù),docker,架構(gòu)

此時,最終用戶已經(jīng)可以看到電影院有哪些電影首映,可以選擇電影院并請求預(yù)訂,因此在本文中,我們將繼續(xù)構(gòu)建電影院架構(gòu),我們將看到預(yù)訂服務(wù)內(nèi)部發(fā)生了什么,所以跟進??,讓我們學習一些有趣的事情。

我們將在本文中使用的是:

  • NodeJS 版本 7.5.0
  • MongoDB 3.4.1
  • Docker for Mac 1.13

跟進文章的先決條件:

  • 已完成上一章中的示例。

如果你還沒有,我已經(jīng)上傳了一個 github 存儲庫,所以你可以在分支步驟 2?上獲得最新的存儲庫鏈接。

三、NodeJS 中的依賴注入

????????到目前為止,我們已經(jīng)為我們的微服務(wù)構(gòu)建了 2 個 API,但在這些微服務(wù)中,我們還沒有做太多的配置和這么多的開發(fā),因為它的性質(zhì)和簡單性,但這一刻已經(jīng)到來,在我們的預(yù)訂微服務(wù)中,我們將看到與其他服務(wù)更多的交互,為此我們將需要更多的依賴項來完成分配給此微服務(wù)的任務(wù), 但是為了不開始制作一些意大利面條代碼,作為優(yōu)秀的開發(fā)人員,我們將跟進一些??開發(fā)設(shè)計模式,為此我們將看到什么是“依賴注入”。

為了實現(xiàn)優(yōu)秀的設(shè)計模式,我們必須很好地理解并應(yīng)用S.O.L.I.D.原則,我用javascript寫了一篇關(guān)于這個的文章,所以你可以看一看??,看看這個原則是什么,我們?nèi)绾螐闹惺芤妗?/em>

????????在我們開始討論依賴注入之前,如果您不熟悉它,可以在繼續(xù)之前觀看以下視頻。

依賴關(guān)系注入是一種軟件設(shè)計模式,其中一個或多個依賴關(guān)系(或服務(wù))被注入或通過引用傳遞到依賴對象中。

????????為什么理解什么是依賴注入很重要?,這很重要,因為它為我們提供了開發(fā)模式中的 3 個要點,如下所示:

  • 解耦:依賴注入使我們的模塊耦合更少,并且隨著它的實現(xiàn),我們獲得了主要的可維護性。
  • 單元測試:通過依賴注入,我們可以為每個模塊進行更好的單元測試,我們的代碼也會減少錯誤。
  • 更快的開發(fā):通過依賴注入,在定義接口后,可以輕松工作,沒有任何合并沖突。

因此,到目前為止,在我們的微服務(wù)中,我們已經(jīng)在index.js

// more code

mediator.on('db.ready', (db) => {
  let rep
  // here we are making DI to the repository
  // we are injecting the database object and the ObjectID object
  repository.connect({
    db, 
    ObjectID: config.ObjectID
  })
  .then(repo => {
      console.log('Connected. Starting Server')
      rep = repo
      // here we are also making DI to the server
      // we are injecting serverSettings and the repo object
      return server.start({
        port: config.serverSettings.port,
        ssl: config.serverSettings.ssl,
        repo
      })
    })
    .then(app => {
      console.log(`Server started succesfully, running on port: ${config.serverSettings.port}.`)
      app.on('close', () => {
        rep.disconnect()
      })
    })
})

// more code

????????我們在文件中所做的是手動DI,因為我們不需要做更多的事情,但是知道在預(yù)訂服務(wù)中,我們需要制定更好的DI方法,讓我們看看為什么我們需要它,所以在我們開始構(gòu)建API之前,讓我們弄清楚預(yù)訂服務(wù)需要做什么。index.js

  • 預(yù)訂服務(wù)需要一個預(yù)訂對象和一個用戶對象,在執(zhí)行預(yù)訂操作后,我們需要首先驗證這些對象。
  • 一旦驗證,我們就能夠繼續(xù)開始購買門票的過程。
  • 預(yù)訂服務(wù)需要用戶信用卡信息才能通過支付服務(wù)購買門票。
  • 成功收費后,我們需要通過通知服務(wù)發(fā)送通知。
  • 此外,我們需要為用戶生成票證,將票證和采購訂單ID代碼發(fā)送回給用戶。

????????因此,這里的開發(fā)任務(wù)已經(jīng)增加了一點,因此代碼也會增加,這就是為什么我們需要為DI創(chuàng)建單一事實來源的原因,因為我們將要做更多的功能。

四、構(gòu)建微服務(wù)

????????好的,首先讓我們看看我們的RAML文件將如何用于預(yù)訂服務(wù)。

#%RAML 1.0
title: Booking Service
version: v1
baseUri: /

types:
  Booking:
    properties:
      city: string
      cinema: string
      movie: string
      schedule: datetime
      cinemaRoom: string
      seats: array
      totalAmount: number


  User:
    properties:
      name: string
      lastname: string
      email: string
      creditcard: object
      phoneNumber?: string
      membership?: number

  Ticket:
    properties:
      cinema: string
      schedule: string
      movie: string
      seat: string
      cinemaRoom: string
      orderId: string


resourceTypes:
  GET:
    get:
      responses:
        200:
          body:
            application/json:
              type: <<item>>

  POST:
    post:
      body:
        application/json:
          type: <<item>>
          type: <<item2>>
      responses:
        201:
          body:
            application/json:
              type: <<item3>>


/booking:
  type:   { POST: {item : Booking, item2 : User, item3: Ticket} }
  description: The booking service need a Booking object that contains all
    the needed information to make a purchase of cinema tickets.
    Needs a user information to make the booking succesfully.
    And returns a ticket object.

  /verify/{orderId}:
    type:  { GET: {item : Ticket} }
    description: This route is for verify orders, and would return all the details
      of a specific purchased by orderid.

????????我們定義了 3 個模型對象,即預(yù)訂、用戶票證,因此由于這是我們在本系列中看到的第一個?POST?請求,因此有一個我們尚未使用的 NodeJS?最佳實踐,即數(shù)據(jù)驗證。?我從文章“構(gòu)建漂亮的節(jié)點API”中讀到了一個很好的引用,其中說了以下內(nèi)容:

????????因此,我們將從這里開始構(gòu)建我們的預(yù)訂服務(wù)。與上一章一樣,我們?nèi)詫⑹褂孟嗤捻椖拷Y(jié)構(gòu),但這次我們將進行更多的修改。所以讓我們停止談?wù)??理論,讓饑餓游戲開始,再次抱歉,所以讓樂趣開始讓我們做一些“編碼!??????????????.

????????首先,我們需要在名為/srcmodels

booking-service/src $ mkdir models
# Now let's move to the folder and create some files
booking-service/src/models $ touch user.js booking.js ticket.js
# Now is moment to install a new npm package for data validation
npm i -S joi --silent

????????好的,現(xiàn)在我們已經(jīng)準備好了,是時候開始編碼我們的模式驗證對象了,MongoDB?也內(nèi)置了一個驗證對象,但這里我們需要驗證的是對象是完整的,這就是我選擇 joi 的原因,joi 也允許我們同時驗證數(shù)據(jù),所以讓我們從 開始,最后從booking.model.jsticket.model.jsuser.model.js

const bookingSchema = (joi) => ({
  bookingSchema: joi.object().keys({
    city: joi.string(),
    schedule: joi.date().min('now'),
    movie: joi.string(),
    cinemaRoom: joi.number(),
    seats: joi.array().items(joi.string()).single(),
    totalAmount: joi.number()
  })
})

module.exports = bookingSchema
const ticketSchema = (joi) => ({
  ticketSchema: joi.object().keys({
    cinema: joi.string(),
    schedule: joi.date().min('now'),
    movie: joi.string(),
    seat: joi.array().items(joi.string()).single(),
    cinemaRoom: joi.number(),
    orderId: joi.number()
  })
})

module.exports = ticketSchema
const userSchema = (joi) => ({
  userSchema: joi.object().keys({
    name: joi.string().regex(/^[a-bA-B]+/).required(),
    lastName: joi.string().regex(/^[a-bA-B]+/).required(),
    email: joi.string().email().required(),
    phoneNumber: joi.string().regex(/^(\+0?1\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/),
    creditCard: joi.string().creditCard().required(),
    membership: joi.number().creditCard()
  })
})

module.exports = userSchema

如果你不知道,你可以在這里查看他們的github文檔:鏈接到文檔。joi

現(xiàn)在,讓我們對模型進行編碼,以公開如下所示的驗證函數(shù):index.js

const joi = require('joi')
const user = require('./user.model')(joi)
const booking = require('./booking.model')(joi)
const ticket = require('./ticket.model')(joi)

const schemas = Object.create({user, booking, ticket})

const schemaValidator = (object, type) => {
  return new Promise((resolve, reject) => {
    if (!object) {
      reject(new Error('object to validate not provided'))
    }
    if (!type) {
      reject(new Error('schema type to validate not provided'))
    }

    const {error, value} = joi.validate(object, schemas[type])

    if (error) {
      reject(new Error(`invalid ${type} data, err: ${error}`))
    }
    resolve(value)
  })
}

module.exports = Object.create({validate: schemaValidator})

????????因此,我們所做的,我們應(yīng)用了單一責任,從每個模型都有自己的驗證的堅實原則,我們還應(yīng)用了開-關(guān)原則,其中模式驗證器函數(shù)能夠驗證我們聲明的任意數(shù)量的模型,所以讓我們看看這個模型的測試文件如何。

/* eslint-env mocha */
const test = require('assert')
const {validate} = require('./')

console.log(Object.getPrototypeOf(validate))

describe('Schemas Validation', () => {
  it('can validate a booking object', (done) => {
    const now = new Date()
    now.setDate(now.getDate() + 1)

    const testBooking = {
      city: 'Morelia',
      cinema: 'Plaza Morelia',
      movie: 'Assasins Creed',
      schedule: now,
      cinemaRoom: 7,
      seats: ['45'],
      totalAmount: 71
    }

    validate(testBooking, 'booking')
      .then(value => {
        console.log('validated')
        console.log(value)
        done()
      })
      .catch(err => {
        console.log(err)
        done()
      })
  })

  it('can validate a user object', (done) => {
    const testUser = {
      name: 'Cristian',
      lastName: 'Ramirez',
      email: 'cristiano@nupp.com',
      creditCard: '1111222233334444',
      membership: '7777888899990000'
    }

    validate(testUser, 'user')
      .then(value => {
        console.log('validated')
        console.log(value)
        done()
      })
      .catch(err => {
        console.log(err)
        done()
      })
  })

  it('can validate a ticket object', (done) => {
    const testTicket = {
      cinema: 'Plaza Morelia',
      schedule: new Date(),
      movie: 'Assasins Creed',
      seats: ['35'],
      cinemaRoom: 1,
      orderId: '34jh1231ll'
    }

    validate(testTicket, 'ticket')
      .then(value => {
        console.log('validated')
        console.log(value)
        done()
      })
      .catch(err => {
        console.log(err)
        done()
      })
  })
})

????????下一個要審查的文件將是?在這一點上,我們開始陷入很多麻煩,為什么?,因為在這里我們將與兩個外部服務(wù)進行交互,支付服務(wù)和通知服務(wù),這種交互可以引導我們重新思考微服務(wù)的架構(gòu), 有一個叫做事件驅(qū)動的數(shù)據(jù)管理和?CQRS,但這些主題將被保存到本系列的后續(xù)章節(jié)中,并且不會使本章變得冗長和復(fù)雜,因此,在此期間,讓我們簡化與本章服務(wù)的交互。api/booking.js

'use strict'
const status = require('http-status')

module.exports = ({repo}, app) => {
  app.post('/booking', (req, res, next) => {
    
    // we grab the dependencies need it for this route
    const validate = req.container.resolve('validate')
    const paymentService = req.container.resolve('paymentService')
    const notificationService = req.container.resolve('notificationService')

    Promise.all([
      validate(req.body.user, 'user'),
      validate(req.body.booking, 'booking')
    ])
    .then(([user, booking]) => {
      const payment = {
        userName: user.name + ' ' + user.lastName,
        currency: 'mxn',
        number: user.creditCard.number,
        cvc: user.creditCard.cvc,
        exp_month: user.creditCard.exp_month,
        exp_year: user.creditCard.exp_year,
        amount: booking.amount,
        description: `
          Tickect(s) for movie ${booking.movie},
          with seat(s) ${booking.seats.toString()}
          at time ${booking.schedule}`
      }

      return Promise.all([
        // we call the payment service
        paymentService(payment),
        Promise.resolve(user),
        Promise.resolve(booking)
      ])
    })
    .then(([paid, user, booking]) => {
      return Promise.all([
        repo.makeBooking(user, booking),
        repo.generateTicket(paid, booking)
      ])
    })
    .then(([booking, ticket]) => {
      // we call the notification service
      notificationService({booking, ticket})
      res.status(status.OK).json(ticket)
    })
    .catch(next)
  })

  app.get('/booking/verify/:orderId', (req, res, next) => {
    repo.getOrderById(req.params.orderId)
      .then(order => {
        res.status(status.OK).json(order)
      })
      .catch(next)
  })
}

????????正如你在這里看到的,我們正在使用 expressjs?中間件,我們正在利用從單一事實來源注冊依賴項容器。

????????但是DI容器在哪里?

????????好吧,我們對項目結(jié)構(gòu)進行了一些更改,主要是在文件夾中,現(xiàn)在如下所示:config

. 
|-- config 
|   |-- db 
|   |   |-- index.js 
|   |   |-- mongo.js 
|   |   `-- mongo.spec.js 
|   |-- di 
|   |   |-- di.js 
|   |   `-- index.js 
|   |-- ssl
|   |   |-- certificates 
|   |   `-- index.js
|   |-- config.js
|   |-- index.spec.js 
|   `-- index.js

????????在文件中,我們主要包括所有配置以及?DI?服務(wù):config/index.js

const {dbSettings, serverSettings} = require('./config')
const database = require('./db')
const {initDI} = require('./di')
const models = require('../models')
const services = require('../services')
const init = initDI.bind(null, {serverSettings, dbSettings, database, models, services})
module.exports = Object.assign({}, {init})

????????在上面的代碼中,我們看到了一些罕見的東西,讓我再次為您縮放它:

initDI.bind(null, {serverSettings, dbSettings, database, models, services})

????????我們在這里做什么?,我說我們正在配置 DI,但在這里我們正在制作一種叫做控制反轉(zhuǎn)的東西,是的,是的,我知道這是很多技術(shù)術(shù)語,可能聽起來很臃腫,但它很容易理解,一旦你得到它,如果你還沒有聽說過?IoC,我建議你觀看以下視頻:

????????所以我們的?DI?函數(shù)不需要知道我們的依賴項來自哪里,它只需要注冊我們的依賴項即可在我們的應(yīng)用程序中使用,所以我們的文件如下所示:di.js

const { createContainer, asValue, asFunction, asClass } = require('awilix')

function initDI ({serverSettings, dbSettings, database, models, services}, mediator) {
  mediator.once('init', () => {
    mediator.on('db.ready', (db) => {
      const container = createContainer()
      
      // loading dependecies in a single source of truth
      container.register({
        database: asValue(db).singleton(),
        validate: asValue(models.validate),
        booking: asValue(models.booking),
        user: asValue(models.booking),
        ticket: asValue(models.booking),
        ObjectID: asClass(database.ObjectID),
        serverSettings: asValue(serverSettings),
        paymentService: asValue(services.paymentService),
        notificationService: asValue(services.notificationService)
      })
      
      // we emit the container to be able to use it in the API
      mediator.emit('di.ready', container)
    })

    mediator.on('db.error', (err) => {
      mediator.emit('di.error', err)
    })

    database.connect(dbSettings, mediator)

    mediator.emit('boot.ready')
  })
}

module.exports.initDI = initDI

????????如您所見,我們正在使用一個名為依賴注入的 npm 包,awilix 在 nodejs 中實現(xiàn)了依賴注入的機制(我目前正在評估這個庫,但我在這里使用它來說明示例),所以要安裝它,我們需要執(zhí)行下一個命令:awilix

npm i -S awilix --silent

????????要進一步了解 awilix 的工作原理,您可以查看作者在以下鏈接中撰寫的依賴注入系列文章:DI 系列和?awilix 文檔。

????????現(xiàn)在或主文件將如下所示:index.js

'use strict'
const {EventEmitter} = require('events')
const server = require('./server/server')
const repository = require('./repository/repository')
const di = require('./config')
const mediator = new EventEmitter()

console.log('--- Booking Service ---')
console.log('Connecting to movies repository...')

process.on('uncaughtException', (err) => {
  console.error('Unhandled Exception', err)
})

process.on('uncaughtRejection', (err, promise) => {
  console.error('Unhandled Rejection', err)
})

mediator.on('di.ready', (container) => {
  repository.connect(container)
    .then(repo => {
      container.registerFunction({repo})
      return server.start(container)
    })
    .then(app => {
      app.on('close', () => {
        container.resolve('repo').disconnect()
      })
    })
})

di.init(mediator)

mediator.emit('init')

????????正如你現(xiàn)在看到的,我們只使用一個單一的事實來源,它有我們需要的所有依賴項,可以通過容器請求它,那么我們?nèi)绾螌⑵湓O(shè)置為expressjs中間件,就像之前注釋的那樣,它只是幾行代碼:

const express = require('express')
const morgan = require('morgan')
const helmet = require('helmet')
const bodyparser = require('body-parser')
const cors = require('cors')
const spdy = require('spdy')
const _api = require('../api/booking')

const start = (container) => {
  return new Promise((resolve, reject) => {
    
    // here we grab our dependencies needed for the server
    const {repo, port, ssl} = container.resolve('serverSettings')

    if (!repo) {
      reject(new Error('The server must be started with a connected repository'))
    }
    if (!port) {
      reject(new Error('The server must be started with an available port'))
    }

    const app = express()
    app.use(morgan('dev'))
    app.use(bodyparser.json())
    app.use(cors())
    app.use(helmet())
    app.use((err, req, res, next) => {
      if (err) {
        reject(new Error('Something went wrong!, err:' + err))
        res.status(500).send('Something went wrong!')
      }
      next()
    })
    
    // here is where we register the container as middleware
    app.use((req, res, next) => {
      req.container = container.createScope()
      next()
    })
    
    // here we inject the repo to the API, since the repo is need it for all of our functions
    // and we are using inversion of control to make it available
    const api = _api.bind(null, {repo: container.resolve('repo')})
    api(app)

    if (process.env.NODE === 'test') {
      const server = app.listen(port, () => resolve(server))
    } else {
      const server = spdy.createServer(ssl, app)
        .listen(port, () => resolve(server))
    }
  })
}

????????所以基本上我們將容器對象附加到 expressjs?req 對象,這就是我們?nèi)绾瓮ㄟ^所有 expressjs 路由使用它。如果你想更深入地了解中間件如何與 expressjs 一起工作,你可以訪問此鏈接并查看 expressjs 文檔。

嗯,有句話說,越好越好,最后我們要審查文件:repository.js

'use strict'
const repository = (container) => {
  // we get the db object via the container
  const {db} = container.resolve('database')

  const makeBooking = (user, booking) => {
    return new Promise((resolve, reject) => {
      // payload to be insterted to the booking collection 
      const payload = {
        city: booking.city,
        cinema: booking.cinema,
        book: {
          userType: (user.membership) ? 'loyal' : 'normal',
          movie: {
            title: booking.movie.title,
            format: booking.movie.format,
            schedule: booking.schedule
          }
        }
      }

      db.collection('booking').insertOne(payload, (err, booked) => {
        if (err) {
          reject(new Error('An error occuered registring a user booking, err:' + err))
        }
        resolve(booked)
      })
    })
  }

  const generateTicket = (paid, booking) => {
    return new Promise((resolve, reject) => {
      // payload of ticket
      const payload = Object.assign({}, {booking, orderId: paid._id})
      db.collection('tickets').insertOne(payload, (err, ticket) => {
        if (err) {
          reject(new Error('an error occured registring a ticket, err:' + err))
        }
        resolve(ticket)
      })
    })
  }

  const getOrderById = (orderId) => {
    return new Promise((resolve, reject) => {
      const ObjectID = container.resolve('ObjectID')
      const query = {_id: new ObjectID(orderId)}
      const response = (err, order) => {
        if (err) {
          reject(new Error('An error occuered retrieving a order, err: ' + err))
        }
        resolve(order)
      }
      db.collection('booking').findOne(query, {}, response)
    })
  }

  const disconnect = () => {
    db.close()
  }

  return Object.create({
    makeBooking,
    getOrderById,
    generateTicket,
    disconnect
  })
}

const connect = (container) => {
  return new Promise((resolve, reject) => {
    if (!container.resolve('database')) {
      reject(new Error('connection db not supplied!'))
    }
    resolve(repository(container))
  })
}

module.exports = Object.assign({}, {connect})

????????好的,所以在我們的相關(guān)性上沒有太多的相關(guān)性,可能是我們第一次在系列中使用該方法,但是我想在這個文件中指出一件事,特別是在方法上,如果您看到有效負載對象,這是集合數(shù)據(jù)模型模式,但為什么? 為什么我們會使用這種方法,如果我們使用它,我們不是會重復(fù)很多信息嗎?repository.jsinsertOne()makeBooking()

????????嗯,是的,我們將重復(fù)信息,這不是最佳做法,但這是有原因的,直到下次??我才會告訴你,為什么是因為該系列有一些非常有趣的東西......

????????如果你想要一個提示,我會留下這個給你好奇 ??

   ----------------------------------------
  |                                        |
  |                                        v
  |                       Jane  ------(went to)----------
  |                         |                            |
  |                         | (loyal vistor)             |
  |                         v                            v
 Joe --(normal visitor)--> Movie Name <--(displayed)-- Plaza Morelia
                             |                           |
                             |  (format)                 | (city)
                             v                           v
                            4DX                       Morelia

????????如果您能發(fā)現(xiàn)即將發(fā)生的事情,歡迎您在評論部分發(fā)表評論。

????????好吧,讓我們繼續(xù),我們已經(jīng)評論說我們正在與兩個外部服務(wù)進行交互,為簡單起見,讓我們看看我們需要從這些外部服務(wù)中獲得什么

# for the payment service we will need to implement something like the following
module.exports = (paymentOrder) => {
  return new Promise((resolve, reject) => {
    supertest('url to the payment service')
      .get('/makePurchase')
      .send({paymentOrder})
      .end((err, res) => {
        if (err) {
          reject(new Error('An error occured with the payment service, err: ' + err))
        }
        resolve(res.body.payment)
      })
  })
}
# since we haven't made the payment service yet, let's make something simple to fulfill the article example, like the following    
module.exports = (paymentOrder) => {
  return new Promise((resolve, reject) => {
    resolve({orderId: Math.floor((Math.random() * 1000) + 1)})
  })
}
# for the notification service, at the moment we don't need any information from this service we will not implement it, this service will have the task for sending an email, sms or another notification, but we will make this service in the next chapter.

????????好吧,我們已經(jīng)完成了這個微服務(wù)的構(gòu)建,所以,現(xiàn)在是時候使用以下命令在存儲庫中執(zhí)行文件了:

$ bash < start_service

????????讓我們的微服務(wù)準備就緒并完全正常運行到 docker 容器中,并開始進行集成測試

五、是時候回顧一下了

????????我們做了什么...?如果您遵循了我之前的章節(jié),我們有一個如下系統(tǒng)架構(gòu):

構(gòu)建 NodeJS 影院預(yù)訂微服務(wù)并使用 docker 部署(03/4),docker,微服務(wù),docker,架構(gòu)
影院系統(tǒng)架構(gòu)

????????如果你注意到我們的系統(tǒng)開始成形,但有些東西讓我們感覺不對,那就是在工作線程 1 和工作線程?2?中,我們沒有任何微服務(wù)運行,那是因為我們沒有在其中創(chuàng)建任何服務(wù),但我們很快就會這樣做。docker-machines

????????現(xiàn)在在影院微服務(wù)架構(gòu)中,我們幾乎完成了下圖:

構(gòu)建 NodeJS 影院預(yù)訂微服務(wù)并使用 docker 部署(03/4),docker,微服務(wù),docker,架構(gòu)

我們只是構(gòu)建預(yù)訂服務(wù),然后簡單實現(xiàn)支付服務(wù)和通知服務(wù)。

因此,我們在本章??中學習了依賴注入,我們看到了一點?SOLID 原則和控制反轉(zhuǎn),使用?NodeJS,我們還在微服務(wù)中發(fā)出了第一個?POST 請求,我們還學習了如何使用?joi?庫驗證對象和數(shù)據(jù)。

我們已經(jīng)在?NodeJS?中看到了很多開發(fā),但我們可以做和學習的東西還有很多,這只是一個先睹為快的高峰。我希望這已經(jīng)展示了一些有趣和有用的東西,你可以在你的工作流程中用于Docker和NodeJS。

六、即將推出

????????在接下來的劇集中,我們將創(chuàng)建并完成支付服務(wù)和通知服務(wù)的實現(xiàn),但這不是有趣的部分,有趣的是我們將創(chuàng)建我們的 API 網(wǎng)關(guān),因為我們的影院微服務(wù)開始增長并且微服務(wù)有必要相互通信。但是要擁有一個非常強大的微服務(wù)系統(tǒng)還有很多事情要做,在后面的章節(jié)中,我們將看到如何使十二因素應(yīng)用程序適應(yīng)微服務(wù)。

# 在 Github 上完成代碼

您可以在以下鏈接中查看文章的完整代碼。克里斯蒂安·拉米雷斯文章來源地址http://www.zghlxwxcb.cn/news/detail-663209.html

·

到了這里,關(guān)于構(gòu)建 NodeJS 影院預(yù)訂微服務(wù)并使用 docker 部署(03/4)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 電影院購票預(yù)訂選座系統(tǒng)微信小程序 vimnf

    電影院購票預(yù)訂選座系統(tǒng)微信小程序 vimnf

    ?利用Java語言、Spring Boot框架和mysql數(shù)據(jù)庫等知識點,結(jié)合相關(guān)設(shè)計模式、以及軟件工程的相關(guān)知識,設(shè)計一個電影院購票系統(tǒng),來進行記錄用戶的信息,以及系統(tǒng)信息的增刪改查的功能,根據(jù)實現(xiàn)需求,系統(tǒng)需完成這些基本功能: (1)系統(tǒng)合理顯示首頁、個人中心、用戶管

    2024年01月17日
    瀏覽(23)
  • NodeJs后端項目使用docker打包部署

    NodeJs后端項目使用docker打包部署

    docker安裝看之前的文章 默認已經(jīng)安裝好docker并且配置沒有問題 拉取項目 https://gitee.com/coder-msc/docker-node 本地跑一個看看 pnpm install pnpm start 本地訪問 項目整個上傳服務(wù)器 查看dockerfile 使用docker打包 進入項目目錄里面 docker build . 給鏡像打tag: docker tag b86282a8ba4c node-demo:v1.0.1 啟動

    2024年02月15日
    瀏覽(20)
  • Docker構(gòu)建Java服務(wù) docker-compose部署微服務(wù)

    Docker構(gòu)建Java服務(wù) docker-compose部署微服務(wù)

    目錄 1.? 安裝Docker前置準備 設(shè)置Docker開機自啟動 配置Docker阿里云鏡像加速 安裝Docker-compose 2、鏡像拉取 3、創(chuàng)建docker-comepose.yaml文件 4.? 創(chuàng)建數(shù)據(jù)映射容器掛載目錄 ,以下是nacos?? xxl-job-admin sql腳本文件 5.? docker-comepose 部署 1. 安裝Docker前置準備 設(shè)置Docker開機自啟動 配置Do

    2024年04月16日
    瀏覽(21)
  • Docker技術(shù)入門| Part03:Dockerfile詳解(Dockerfile概念、Dockerfile 指令、使用Dockerfile構(gòu)建鏡像)

    Docker鏡像原理 Docker鏡像是由特殊的文件系統(tǒng)疊加而成 最底端是bootfs,并使用宿主機的bootfs 第二層是root文件系統(tǒng)rootfs,稱為base image 然后再往上可以疊加其他的鏡像文件 統(tǒng)文件系統(tǒng)(UnionFile System)技術(shù)能夠?qū)⒉煌膶诱铣梢粋€文件系統(tǒng),為這些層提供了一個統(tǒng)的視角,這樣就隱

    2024年02月09日
    瀏覽(92)
  • Docker與微服務(wù):構(gòu)建和部署微服務(wù)架構(gòu)的完整指南

    Docker與微服務(wù):構(gòu)建和部署微服務(wù)架構(gòu)的完整指南

    微服務(wù)架構(gòu)已經(jīng)成為現(xiàn)代應(yīng)用開發(fā)的主要范式之一,而Docker容器技術(shù)則為微服務(wù)的構(gòu)建、部署和管理提供了理想的解決方案。本文將深入探討如何使用Docker構(gòu)建和部署微服務(wù)架構(gòu),提供更多示例代碼和細致的指南,以幫助大家更全面地理解和運用這些關(guān)鍵概念。 微服務(wù)架構(gòu)是

    2024年02月02日
    瀏覽(52)
  • DeepFace【部署 03】輕量級人臉識別和面部屬性分析框架deepface在Linux環(huán)境下服務(wù)部署(conda虛擬環(huán)境+docker)

    Anaconda的安裝步驟這里不再介紹,直接開始使用。 以下操作在虛擬環(huán)境 deepface 下執(zhí)行: 使用 yum install mesa-libGL.x86_64 命令會在Linux系統(tǒng)中安裝mesa-libGL包。這個包包含了Mesa 3D圖形庫的運行時庫和DRI驅(qū)動。安裝mesa-libGL包后,系統(tǒng)將能夠支持OpenGL,這是一種用于渲染2D和3D矢量圖形

    2024年02月08日
    瀏覽(106)
  • Apache Doris 入門教程03:使用Docker或Kubernetes部署Doris

    該文檔主要介紹了如何通過 Dockerfile 來制作 Apache Doris 的運行鏡像,以便于在容器化編排工具或者快速測試過程中可迅速拉取一個 Apache Doris Image 來完成集群的創(chuàng)建。 概述? Docker 鏡像在制作前要提前準備好制作機器,該機器的平臺架構(gòu)決定了制作以后的 Docker Image 適用的平臺

    2024年02月07日
    瀏覽(22)
  • k8s服務(wù)部署核心流程:以Jenkins為核心,從Gitee拉取代碼,然后進行maven構(gòu)建,之后使用docker命令打鏡像,并推送鏡像到harbor倉庫,之后遠程調(diào)用k8s命令創(chuàng)建服務(wù)

    k8s服務(wù)部署核心流程:以Jenkins為核心,從Gitee拉取代碼,然后進行maven構(gòu)建,之后使用docker命令打鏡像,并推送鏡像到harbor倉庫,之后遠程調(diào)用k8s命令創(chuàng)建服務(wù)

    前提是我們在自己電腦上模擬整個流程。 假設(shè)我們需要搭建一主一從的k8s集群,那就需要安裝VMvare和Centos7(點擊我查看安裝文檔), 然后就可以在這兩個虛擬機上搭建k8s集群了(點擊我查看安裝文檔), 一個最簡單的devops流程已經(jīng)在標題中寫明了, 其中可以搭建gitlab(點

    2024年02月02日
    瀏覽(31)
  • 使用docker構(gòu)建并部署MySQL5.7鏡像

    使用docker構(gòu)建并部署MySQL5.7鏡像

    這幾天在研究如何將服務(wù)器和數(shù)據(jù)庫遷移至 docker容器 ,中間遇到了許多問題,特此寫篇博客記錄一下。 提示:本篇文章主要講解如何在docker容器中構(gòu)建及部署MySQL 從 CentOS 鏡像中構(gòu)建 MySQL 容器 從 MySQL 官方鏡像中構(gòu)建容器 從 CentOS 鏡像中構(gòu)建 MySQL 容器可以更好地控制操作系

    2024年02月03日
    瀏覽(94)
  • 03-微服務(wù)架構(gòu)構(gòu)建之微服務(wù)拆分

    微服務(wù)架構(gòu)是將一個單體應(yīng)用程序拆分為一個個獨立且保持松耦合的服務(wù)的一種架構(gòu)方式,每個服務(wù)有著獨立的數(shù)據(jù)庫并且能獨立運行部署。微服務(wù)架構(gòu)的構(gòu)建過程中,第一步也是最為重要的一步是進行服務(wù)拆分。只有將微服務(wù)按照合理的方式進行拆分,才能確保整個項目能

    2024年02月03日
    瀏覽(59)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包