dcProfile := map[string]string{
"name": "Daniel Caballero",
"title": "Staff Devops Engineer",
"mail": "dani(dot)caba at gmail(dot)com",
"company": &SchibstedPT,
"previously_at": []company{&NTTEurope, &Semantix, &Oracle},
"linkedin": http.Get("https://www.linkedin.com/in/danicaba"),
"extra": "Gestión DevOps de Arquitecturas IT@LaSalle",
}
{
"format": "jpg",
"watermark": {
"location": "north",
"margin": "20px",
"dimension": "20%"
},
"actions": [
{
"resize": {
"width": 300,
"fit": {
"type": "clip"
}
}
}
],
"quality": 90
}
language: go
go:
- 1.9.3
script:
- diff -u <(echo -n) <(gofmt -s -d $(find . -type f -name '*.go' -not -path "./vendor/*"))
- docker login -u="$ARTIFACTORY_USER" -p="$ARTIFACTORY_PASSWORD" containers.schibsted.io
- "./requirements/start-requirements.sh -d"
- "_script/tests-docker"
- "_script/compile-docker"
- "_script/cibuild"
deploy:
skip_cleanup: true
on:
all_branches: true
provider: script
script: _script/deploy
fpm -s dir \
-t rpm \
-n ${PACKAGE_NAME}${DEV} \
-v ${VERSION} \
--iteration ${ITERATION} \
--description "Yams delivery images. Commit: ${GIT_COMMIT_ID}" \
--before-install ${TRAVIS_BUILD_DIR}/_pkg/stopservice \
--after-install ${TRAVIS_BUILD_DIR}/_pkg/postinst \
--before-remove ${TRAVIS_BUILD_DIR}/_pkg/stopservice \
--depends datadog-config \
--depends sumologic-config \
${DIST_PATH}/${PACKAGE_NAME}/=/
Using logrus in delivery-images
pre:
not_allowed_notify_to:
- "@webhook-alert-gateway-sev2"
- "@pagerduty"
healthy_host_count_critical: 0.0
pro:
healthy_host_count_critical: 1.0
monitors:
- name: "[ALB] - {{name.name}} in region {{region.name}} - 5xx backend error rate"
tags:
- "app:yams"
type: "metric alert"
options:
require_full_window: false
thresholds:
warning: 0.05
critical: 0.1
notify_no_data: false
n := negroni.New(recovery)
n.Use(NewRequestIdHandler())
n.Use(tracing.NewTracingHandler())
n.Use(negroni.NewStatic(http.Dir(serverConfig.schemaDir)))
loggingMiddleware := negronilogrus.NewMiddlewareFromLogger(serverConfig.log, "bumblebee")
loggingMiddleware.SetLogStarting(false)
n.Use(loggingMiddleware)
n.Use(statsMiddleware)
n.UseHandler(httpRouter)
return n
if transformedImage.FromCache {
b.Logger.WithField("id", requestId).Debug("Found Transformation in cache")
tracing.AddLogToSpanInContext(request.Context(), "Got image from cache")
b.Monitor.Incr("transformation.cache.hit", tags, 1)
} else {
b.Monitor.Incr("transformation.cache.miss", tags, 1)
transformationElapsed := time.Since(transformationStart)
transformationElapsedInMillis := float64(transformationElapsed.Nanoseconds()) / 1000.0
b.Monitor.TimeInMilliseconds("request.transformation.duration", transformationElapsedInMillis, tags, 1)
b.Monitor.Gauge("request.transformation.duration", transformationElapsedInMillis, tags, 1)
b.Logger.WithField("id", requestId).Debug("Transformation took: ", transformationElapsed.Seconds(), " secs")
tracing.AddLogKvToSpanInContext(request.Context(), "transformation.duration", transformationElapsed.String())
}
viper.SetDefault("eureka.datacenter", amazonDatacenterInfo)
datacenter := viper.GetString("eureka.datacenter")
if datacenter == k8DatacenterInfo {
var err error
appInstance, err = sdeureka.NewK8SFargoInstance(eurekaConfig)
if err != nil {
return nil, nil, err
}
} else if datacenter == amazonDatacenterInfo {
awsSession, err := session.NewSession()
if err != nil {
log.Info("registerEureka", "error creating an AWS session", "message", err)
return nil, nil, err
}
instanceMeta := ec2metadata.New(awsSession)
appInstance, err = sdeureka.NewAwsFargoInstance(log, eurekaConfig, instanceMeta)
if err != nil {
return nil, nil, err
}
} else if datacenter == localDatacenterInfo {
var err error
appInstance, err = sdeureka.NewLocalFargoInstance(eurekaConfig)
if err != nil {
return nil, nil, err
}
hystrix.ConfigureCommand("DeliveryImages#GetWatermarkFromLogicManager", hystrix.CommandConfig{
Timeout: viper.GetInt("hystrix.command.DeliveryImagesGetWatermarkFromLogicManager.timeout"),
MaxConcurrentRequests: viper.GetInt("hystrix.command.DeliveryImagesGetWatermarkFromLogicManager.maxConcurrentRequests"),
ErrorPercentThreshold: viper.GetInt("hystrix.command.DeliveryImagesGetWatermarkFromLogicManager.errorPercentThreshold"),
})
hystrix.ConfigureCommand("DeliveryImages#GetResourceByAliasFromTranslator", hystrix.CommandConfig{
Timeout: viper.GetInt("hystrix.command.GetResourceByAliasFromTranslator.timeout"),
MaxConcurrentRequests: viper.GetInt("hystrix.command.GetResourceByAliasFromTranslator.maxConcurrentRequests"),
ErrorPercentThreshold: viper.GetInt("hystrix.command.GetResourceByAliasFromTranslator.errorPercentThreshold"),
})
func httpServer(serverConfig deliveryImagesServer) *negroni.Negroni {
httpRouter := httprouter.New()
httpRouter.GET("/tenants/:tenant_id/domains/:domain_id/buckets/:bucket_id/images/*image_id", serverConfig.bumblebeeController.Handler)
httpRouter.HEAD("/tenants/:tenant_id/domains/:domain_id/buckets/:bucket_id/images/*image_id", serverConfig.bumblebeeController.Handler)
httpRouter.POST("/schema/validate", serverConfig.schemaController.Handler)
httpRouter.GET("/healthcheck", serverConfig.healtcheckHandler)
hystrixStreamHandler := hystrix.NewStreamHandler()
hystrixStreamHandler.Start()
httpRouter.GET("/hystrix.stream", hystrixStream(hystrixStreamHandler))
We strongly rely on autoscaling:
Deregistering instances makes scale-downs cleaner
imageType := bimg.DetermineImageType(imageToTransform.Buffer())
tracing.AddLogToSpanInContext(transformationRequest.Context, "Imagetype: "+bimg.ImageTypeName(imageType))
autoRotate := getAutoRotateFromRule(rule)
if autoRotate {
err = imageToTransform.AutoRotate()
if err != nil {
t.Log.WithField("id", transformationRequest.RequestId).Errorf("Failed to apply autorotation. Error: %v", err)
return TransformedImage{}, err
}
}
imageToTransform, err = t.applyBlurring(imageToTransform, transformationRequest)
if err != nil {
t.Log.WithField("id", transformationRequest.RequestId).Errorf("Failed to apply blurring. Error: %v", err)
return TransformedImage{}, err
}
if err = t.applyPixelation(imageToTransform, transformationRequest); err != nil {
t.Log.WithField("id", transformationRequest.RequestId).Errorf("Failed to apply pixelation. Error: %v", err)
return TransformedImage{}, err
}
func (t *VipsTransformer) applyPixelation(imageToTransform *bimg.SchImage, transformationRequest TransformationRequest) error {
if len(transformationRequest.Rule.GetPixelateAreas()) == 0 {
return nil
}
start := time.Now()
pixelAreas := make([]bimg.PixelateArea, len(transformationRequest.Rule.GetPixelateAreas()))
for i, pixelArea := range transformationRequest.Rule.GetPixelateAreas() {
pixelAreas[i] = bimg.PixelateArea{
Left: pixelArea.Left,
Top: pixelArea.Top,
Width: pixelArea.Width,
Height: pixelArea.Height,
MinNrOfPixels: pixelArea.MinNrOfPixels,
MinPixelSize: pixelArea.MinPixelSize,
}
}
defer t.metrics("pixelate", transformationRequest.Context, transformationRequest.RequestId, start)
return imageToTransform.Pixelate(pixelAreas)
}
Be careful with...
Caching does help
Mind S3 VPC endpoints!!
We may.
And it may be a good moment to consider opencensus.
% go test -bench . -benchtime 30s -timeout 30m
goos: linux
goarch: amd64
pkg: github.schibsted.io/daniel-caballero/documentsConversionTests
BenchmarkConvertAllFiles/localUnoconv/CV-Templates-Curriculum-Vitae.doc-4 30 1335211165 ns/op
BenchmarkConvertAllFiles/directLibreOffice/CV-Templates-Curriculum-Vitae.doc-4 50 812129343 ns/op
BenchmarkConvertAllFiles/justCopy/CV-Templates-Curriculum-Vitae.doc-4 20000 2100841 ns/op
BenchmarkConvertAllFiles/localUnoconv/CV-Templates-Curriculum-Vitae_with_Large_Pic.doc-4 5 7936095889 ns/op
BenchmarkConvertAllFiles/directLibreOffice/CV-Templates-Curriculum-Vitae_with_Large_Pic.doc-4 5 7033935000 ns/op
BenchmarkConvertAllFiles/justCopy/CV-Templates-Curriculum-Vitae_with_Large_Pic.doc-4 2000 29097488 ns/op
BenchmarkConvertAllFiles/localUnoconv/CV-Templates-Curriculum-Vitae_with_Small_Pic.doc-4 30 1273404605 ns/op
BenchmarkConvertAllFiles/directLibreOffice/CV-Templates-Curriculum-Vitae_with_Small_Pic.doc-4 100 673872470 ns/op
BenchmarkConvertAllFiles/justCopy/CV-Templates-Curriculum-Vitae_with_Small_Pic.doc-4 30000 1455526 ns/op
BenchmarkConvertAllFiles/localUnoconv/CVTemplate.odt-4 20 1698359980 ns/op
BenchmarkConvertAllFiles/directLibreOffice/CVTemplate.odt-4 50 1057170276 ns/op
BenchmarkConvertAllFiles/justCopy/CVTemplate.odt-4 30000 1560396 ns/op
BenchmarkConvertAllFiles/localUnoconv/CVTemplate_with_Large_Pic.odt-4 5 7347933754 ns/op
BenchmarkConvertAllFiles/directLibreOffice/CVTemplate_with_Large_Pic.odt-4 10 6864524329 ns/op
BenchmarkConvertAllFiles/justCopy/CVTemplate_with_Large_Pic.odt-4 2000 30033113 ns/op
BenchmarkConvertAllFiles/localUnoconv/CVTemplate_with_Small_Pic.odt-4 20 1669373873 ns/op
Some major Marketplaces are not using the service, yet
Zuul could be replaced by Krakend
Hoverfly: similar in concept to the Simian Army from Netflix, but specialized in API degradations
func main() {
defaultMonthsArg := 1
monthsFlag := NewIntFlag(&defaultMonthsArg)
weeksFlag := NewIntFlag(nil)
flag.Var(&monthsFlag, "months", "How many months to go back. Default is applied if weeks are not specified.")
flag.Var(&weeksFlag, "weeks", "How many weeks to go back. Incompatible with the months argument.")
debugPtr := flag.Bool("debug", false, "Print debugging information to standard error.")
outputPtr := flag.String("output", "text", "Define type of output {text|csv}.")
apiVersionPtr := flag.String("apiversion", "all", "API version to take into account: {all|v1|v0}.")
// default matches YAMS-team conventions
profilePtr := flag.String("profile", "spt-ms-pro", "Profile from your aws config files you want to use.")
engineersPtr := flag.Int("nengineers", 2, "Number of engineers maintaining the service.")
ddMonthCostPtr := flag.Int("ddogmonthlycost", 4000, "Datadog monthly cost (US $) you want to consider.")
sumoMonthCostPtr := flag.Int("sumomonthlycost", 16000, "Sumologic monthly cost (US $) you want to consider.")
flag.Parse()
if monthsFlag.wasSet && weeksFlag.wasSet {
output.PrintError("You cannot use months AND weeks arguments at the same time")
os.Exit(2)
}
Again, go benchmark:
% ./_script/run_benchmark
goos: linux
goarch: amd64
pkg: github.schibsted.io/platform-services/yams-classifier-endtoendtest
BenchmarkUploadAndClassifyAllFiles/2MB.jpg-4 50 1715680610 ns/op
BenchmarkUploadAndClassifyAllFiles/6MB.jpg-4 30 2427555276 ns/op
BenchmarkUploadAndClassifyAllFiles/lbc_large_1_8MB.jpg-4 50 2132103767 ns/op
BenchmarkUploadAndClassifyAllFiles/lbc_large_2_8MB.jpg-4 30 3191113451 ns/op
BenchmarkUploadAndClassifyAllFiles/testCardSmall.jpg-4 100 801532429 ns/op
PASS
ok github.schibsted.io/platform-services/yams-classifier-endtoendtest 506.423s
It almost includes a YAMS SDK
yamsConfig, err := yamscfgfile.NewYamsConfig()
if err != nil {
b.Fatal(err)
}
yamsClient := yamssdk.NewYamsClient(yamsConfig)
...
imageUrls, reqId, err := yamsClient.Upload(fileReader, "image/jpeg", daysWeWillPreserveUploadedFiles)
if err != nil {
b.Fatal("Error uploading image", imageFilename, "against YAMS. Reqid:", reqId,
". Err:", err)
}
classificationResult, err := dataimagesdk.Classify(imageUrls.StaticDeliveryUrl)
...
Sch*
Edge colleagues