Skip to content

Latest commit

 

History

History
318 lines (248 loc) · 7.52 KB

File metadata and controls

318 lines (248 loc) · 7.52 KB

Details

Click to Contract/Expend

How to run

minikube tunnel

# ./ticketing/client
docker build -t pcsmomo/client .
docker push pcsmomo/client # skaffold pull the image from here

# ./ticketing
skaffold dev

kubectl create secret generic jwt-secret --from-literal=JWT_KEY=asdf

add 127.0.0.1 ticketing.dev to /etc/hosts

# temporarily port forwarding NATS services
k get pods

# NATS client
k port-forward nats-depl-588b8b6b8-2s9nt 4222:4222

# NATS mornitoring service (not necessary. For debugging)
k port-forward nats-depl-588b8b6b8-2s9nt 8222:8222
# NATS publisher and listener in separated tabs
npm run publish
npm run listen # x2 or x3, for more listener(=consumer)

Section 17 - Cross-Service Data Replication in Action

356. Scaffolding the Orders Service

  1. Duplicate the 'tickets' service
  2. Install dependencies
  3. Build an image out of the order service
  4. Create a Kubernetes deployment file
  5. Set up file sync options in the skaffold.yaml file
  6. Set up routing rules in the ingress service
# ticketing/orders
npm install
docker build -t pcsmomo/orders .
docker push pcsmomo/orders

357. A Touch More Setup

# ticketing
skaffold dev  # had to run a few times

360. Subtle Service Coupling

We will check ticketId if it is a mongodbID which makes subtle coupling
If you don't like this coupling, this .custom() line can be just deleted

body('ticketId')
  .not()
  .isEmpty()
  .custom((input: string) => mongoose.Types.ObjectId.isValid(input))
  .withMessage('TicketId must be provided');

361. Associating Orders and Tickets

We need to somehow associate Tickets and Orders together
"Ticket Document", "Order Document"
Two primary ways to do this with MongoDB/mongoose

  • Option #1: Embedding
    { ..., "ticket" {} }
    • Querying is a bit challenging
    • There are tickets not ordered, but order service woulnd't know about them
  • Option #2: Mongoose Ref/Population Feature

364. Creating an Order Status Enum

# udemy/microservices-node-react/dwktickets-npm/commmon
npm run pub
# + @dwktickets/common@1.0.7

382. Can We Cancel?

// if it is production, we should not use "!"". It is just for test
expect(updatedOrder!.status).toEqual(OrderStatus.Cancelled);

Section 18 - Understanding Event Flow

385. Creating the Events

# udemy/microservices-node-react/dwktickets-npm/commmon
npm run pub
# + @dwktickets/common@1.0.9
# made a mistake for 1.0.8

# auth, tickets, orders
npm update @dwktickets/common

Section 19 - Listening for Events and Handling Concurrency Issues

400. A Quick Manual Test

Postman manual test

# skaffold dev
# [tickets] Event published to subject ticket:created
# [orders] Message received: ticket:created / orders-service
# [orders] Message received: ticket:updated / orders-service
# [tickets] Event published to subject ticket:updated

401. Clear Concurrency Issues

(Optional) Set up "concurrency-test" script to simulate

  • creating a ticket with price 5
  • modify the price to 10
  • modify the price to 15
  • run them 200 times

Action!

  • Cleanup database
    • tickets-mongo
      # see tickets in
      k get pods
      k exec -it <tickets-mongo-pod> sh
      mongosh
      test> show dbs
      # admin     40.00 KiB
      # config   108.00 KiB
      # local     40.00 KiB
      # tickets   72.00 KiB
      test> use tickets
      tickets> show collections
      # tickets
      tickets> db.tickets.find({})
      # ...
      tickets> db.tickets.remove({})
    • orders-mongo
      # see tickets in
      k get pods
      k exec -it <orders-mongo-pod> sh
      mongosh
      test> show dbs
      # admin    40.00 KiB
      # config  108.00 KiB
      # local    40.00 KiB
      # orders   80.00 KiB
      test> use orders
      orders> show collections
      # orders
      # tickets
      orders> db.tickets.find({})
      # ...
      orders> db.tickets.remove({})
  • Make 600 (3 * 200) requests
    # ticketing/playground/concurrency-test
    npm start
  • Check the database
    # probably the order version of mongodb uses .length()
    orders> db.tickets.find({ price: 10 }).count()
    # 0
    tickets> db.tickets.find({ price: 10 }).count()
    # It should be 0, but when there's concurrent issue.
    # there'd be some tickets with price 10, (wasn't updated to 15)

404. Mongoose Update-If-Current

npm mongoose-update-if-current

# ticketing/tickets
npm install mongoose-update-if-current

mongoose is managing version with __v flag, but we will use version

405. Implementing OCC with Mongoose

Optimistic Concurrency Issue : OCC

// ticketing/tickets/src/models/ticket.ts
ticketSchema.set('versionKey', 'version');

409. Who Updates Versions?

Who should we increment or include the 'version' number of a record with an event?
-> Increment/include the 'version' number whenever the primary service responsible for a record
emits an event to describe a create/update/detroy to a record

410. Including Versions in Events

# udemy/microservices-node-react/dwktickets-npm/commmon
npm run pub
# + @dwktickets/common@1.0.10

# tickets, orders, (auth)
# update package.json first, skaffold will install the version defined in package.json
# "@dwktickets/common": "^1.0.10",
npm update @dwktickets/common

412. Property 'version' is missing TS Errors After Running Skaffold

# ticketing/orders
npm install mongoose-update-if-current

414. Did it Work?

Go to [Simulate 1,200 (3 * 400) requests]

# ticketing/playground/concurrency-test
npm start
tickets> db.tickets.find({ price: 15 }).count()
# 400
orders> db.tickets.find({ price: 15 }).count()
# 400

416. [Optional] Versioning Without Update-If-Current

what does mongoose-update-if-current do

  1. Updates the version number on records before they are saved
    # ticketing/orders/src/events/listeners/ticket-updated-listener.ts
    const { title, price, version } = data;
    ticket.set({ title, price, version });
    await ticket.save();
    
  2. Customizes the find-and-update operation (save) to look for the correct version
    # ticketing/orders/src/events/models/ticket.ts
    // ticketSchema.plugin(updateIfCurrentPlugin);
    // Must use a stand function to bind, not an arrow function
    ticketSchema.pre('save', function (done) {
      this.$where = {
        version: this.get('version') - 1,
      };
      done();
    });
    

433. Publishing While Listening

# udemy/microservices-node-react/dwktickets-npm/commmon
npm run pub
# + @dwktickets/common@1.0.11

# tickets, orders, (auth)
# update package.json first, skaffold will install the version defined in package.json
# "@dwktickets/common": "^1.0.11",
npm update @dwktickets/common

434. Mock Function Arguments

see inside of jest.fn() mock function for debugging

// ticketing/tickets/src/events/listeners/__test__/order-created-listener.test.ts
// @ts-ignore
console.log(natsWrapper.client.publish.mock.calls);

// without @ts-ignore
(natsWrapper.client.publish as jest.Mock).mock.calls[0][1];