Web empire intro

Topics

  • ❔ Who we are
  • 🕢 Brief tech history
  • 🌻 Frontend and GraphQL
  • 🖧 Federated GraphQL
  • ⚙️ Infrastructure
  • 👷 Other services

We are Web Empire

Two teams acting as one

  • two team leads
  • one product
  • one product owner
  • one web
  • one set of ceremonies

 

⚙️ Main parts of our work

📊 Graphql API

📦 Library of
web components

⚙️ Infrastructure

🧮 Administrations

🤩 Mall web

(nearly whole, all langs)

Nearly whole web

  • Everything except Checkout, Payments and Client centre
  • We do not own the data
  • Page types:
    • Homepage
    • Categories
    • Search
    • Shop in Shops
    • Campaigns
    • ....

Original web architecture

Original web architecture

Original web architecture

  • easy to run 
  • only JS and http calls
  • should be faster

🥅 Goal

⚡️Fast web - 📉 3s

💥 Break up monolith

🤖 Modern technologies

🤑 Money

👇

🥰 Happier customers

👇

🧹 Tech debt

🥰 Happier developers

🗿 Stability

🥞 Tech stack

Why nuxt?

  • Great for SSR
  • We need SEO
  • Nuxt - universal application (Nuxt 3 in 6 days 🎉)
    • pros
      • Vue.js
      • SSR
      • Code splitting
      • Apollo
      • Community support
    • cons
      • we want multitenant
      • router
      • translations
  • Typescript (because makes sense with graphql)
  • Fast Integration tests with cypress

SSR HARD PART

 

  • universal applications are different
  • it's a living organism
  • server vs client
  • another process of testing 
  • server render vs client 
    • cookies
    • runtime differences

🕺 Users

  • hybrid rendering
  • optimization for page load
  • balance between what should be SSR and speed
  • mobile vs desktop

🤖 Bots

  • full server side rendering
  • ~70 percent of resources for bots scraping
  • rate limiting

⚡️Render optimization

separated infrastructure for each

⚡️Render optimization

  • smart detection vs dummy
  • new cases for testing
  • we need to be available for bots!
  • user download whole javascript application
  • it's not necessary to reload page between pages
  • new scenarios for testing

🌱 Living organism

🌱 Living organism

  • page can be
    potentially open for weeks
  • be carefull about
    breaking changes

GRAPHQL

  • client 👉  server
  • graphql 👉 typescript 
  • apollo library
  • call only necessary
  • services
  • cache layer
    • server
    • frontend - load once

Graphql what gives us

  • single point of truth
  • one model
  • typescript
  • easy caching
  • circuit breaking
  • performance - get what you want
  • orchestration for services
  • subscriptions (potentially)
  • server side vs client side
  • subscriptions (potentially)

search

customer

cart

bestsellers

banners

menu

category

products

filters

content

Graphql service orchestration

# Calls category
getCategory(categoryUrl: $categoryUrl) {
  id
  howto
  # Calls content service
  ... on ContentCategory {
    content {
      id
      title
      body
    }
  }
  # Calls product service
  ... on ProductCategory {
    productCollection {
      items {
        ... on Product {
          ...productForList
        }
        # Calls estimated delivery service
        ... on BonusSet {
          estimatedDeliveries {
            ...productEstimatedDeliveryFragment
          }
        }
        # Calls banners service
        ... on SectionBannerSlideImage {
          ...sectionBannerSlide
        }
      }
    }
  }
}
  • optimization called
    services
  • call only
    what is necessary
  • next level is federation

Graphql circuit breaker

  • automatically created circuit breakers for resolvers
  • checking stats
  • fail fast
  • fault tolerance

Graphql caching - client side

  • automated vuex
  • cache
  • fetch policies
    • cache-first
    • cache-only
    • cache-and-network
    • network-only
    • no-cache
  • local resolvers/fields

Graphql caching - server side

  • schema level definition
  • automatic resolving of
    cache control
  • redis storage
  • CDN level caching

Graphql differences

  • error handling - show what you can
  • lower rate of requests
  • we can join several queries 
  • be careful about breaking changes❗️

Graphql federation

  • The GQL API service was getting very complex
  • New service meant:
    • API client
    • object mapping
    • GQL resolvers
  • workarounds ( Api Generator )

Graphql federation

  • 💚 One API (URL) composed of many services
  • 💚 New service can be published by config only
  • 💚 Services define entities
    • and can extend them
  • 💔 Integrated services must use GraphQL

Graphql federation

# Service Watchdog

# entity definition
type Watchdog @key(fields: "id") {
    id: ID!
    variantId: String!
    validTo: DateTime
}
# Service loading products 

# entity extension
extend type Watchdog @key(fields: "id") {
	id: ID! @external
	variantId: String! @external
	product: Product @requires(fields: "variantId")
}
# extending service resolver
export default <IResolvers>{
    Watchdog: {
        product: async (
            source: Pick<GqlWatchdog, "variantId">,
            _: {},
            { dataSources }: Context,
        ): Promise<GqlProductExport | null> =>
            dataSources.product.getProductByVariantId(Number(source.variantId)),
    },
};

Other services

~50 services combined

Tech stack:

  • Fronted: Vue, Preact, Quasar
  • Backend: Typescript, PHP, Javascript, Bash
  • Storage: MySQL, MongoDB, Oracle DB
  • Other: RabbitMQ, Redis, Memcache

 

Other services

  • Banner service
  • Campaigns
  • Category management
  • Translation service
  • Content service (rendering)
  • Menu service
  • Redirect service
  • Product recommendations
  • Delivery time estimation
  • ...

 ⚙️ Infrastructure

  • Kubernetes
  • Custom Helm charts
  • Gitlab pipelines
  • Consul
  • ELK stack
  • Prometheus/Karma
  • Grafana
{
  "$schema": "https://gitlab.mallgroup.com/di/helm-deployment-toolkit/-/raw/master/private/helm/charts/mg-generic-lib/release_spec_schema.json",
  "consulServiceName": "mal-transsrv",
  "team": "gf",
  "service": "mal-transsrv",
  "imageRepository": "registry.mallgroup.com/gf/mal-transsrv",
  "imageTag": "95cfaf6d",
  "replicaCount": 3,
  "memory": "600Mi",
  "cpuRequest": "5m",
  "prometheusScrape": true,
  "envs": {
    "DB_CHARSET": "AL32UTF8",
  },
  "vaultSecrets": {
    "env-prod/gf/prod/mal-transsrv": {
      "DB_PASSWORD_SUPER": "DB_PASSWORD_SUPER",
    }
  },
  "sidecars": {
    "redis": {
      "imageRepository": "redis",
      "imageTag": "6.2-alpine",
    }
  }
}

👋 

Web empire introduction

By Radim Štěpaník

Web empire introduction

  • 251