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
-
pros
- 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