{"id":19345378,"url":"https://github.com/kavehmz/jobber","last_synced_at":"2025-04-23T04:36:35.290Z","repository":{"id":57550068,"uuid":"119964016","full_name":"kavehmz/jobber","owner":"kavehmz","description":"Jobber is an implementation to use AWS Lambda functions for micro requests with no penalty ","archived":false,"fork":false,"pushed_at":"2018-03-03T07:19:49.000Z","size":25029,"stargazers_count":16,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-02T08:22:24.068Z","etag":null,"topics":["aws-lambda","golang","grpc","grpc-server","lambda-functions","low-latency","protobuf","schedule"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kavehmz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-02T09:51:51.000Z","updated_at":"2022-10-16T10:34:26.000Z","dependencies_parsed_at":"2022-09-26T18:41:42.729Z","dependency_job_id":null,"html_url":"https://github.com/kavehmz/jobber","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kavehmz%2Fjobber","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kavehmz%2Fjobber/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kavehmz%2Fjobber/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kavehmz%2Fjobber/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kavehmz","download_url":"https://codeload.github.com/kavehmz/jobber/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250372465,"owners_count":21419719,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws-lambda","golang","grpc","grpc-server","lambda-functions","low-latency","protobuf","schedule"],"created_at":"2024-11-10T04:06:29.044Z","updated_at":"2025-04-23T04:36:30.232Z","avatar_url":"https://github.com/kavehmz.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"jobber\n=========\n\n[![Go Lang](http://kavehmz.github.io/static/gopher/gopher-front.svg)](https://golang.org/)\n[![GoDoc](https://godoc.org/github.com/kavehmz/jobber?status.svg)](https://godoc.org/github.com/kavehmz/jobber)\n[![Build Status](https://travis-ci.org/kavehmz/jobber.svg?branch=master)](https://travis-ci.org/kavehmz/jobber)\n[![Coverage Status](https://coveralls.io/repos/kavehmz/jobber/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/kavehmz/jobber?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/github.com/kavehmz/jobber)](https://goreportcard.com/report/github.com/kavehmz/jobber)\n\nJobber is an idea and a sample implementation to use AWS Lambda functions for micro requests\n\n# Background\n\n- Past: Dealing with rigid bare-metal servers. minimum granularity : -\n- Recently - Setting up an auto-scaling environment, using Kubernetes or other tools. Scaling up and down based on incoming requersts. minimum granularity : one VM\n- Today - Using Lambda or Google functions we can scale up to 10,000 cpu in few seconds and then scale down to nothing. minimum granularity: one core, 128MB ram\n\nFor both AWS Lambda and Google cloud functions there are two catches. They have __high startup time__, near 10ms, and they have __minimum 100ms__ time granularity.\n\nIt means if I want to serve my http requests that take 12ms, first I will face near 10ms __delay__ just to start the function,\nthen both platforms will charge me for 100ms of time, even though I just needed 12ms. This makes Cloud function not suitable for\nnormal usage.\n\nHere will eliminate both issues.\n\n# Solution\n\nThe idea is to invoke a Lambda function but instead of asking it to do one request we will __keep it around__ to serve many more with sub microsecond delay. And because it will serve many requests we might not care about 100s time granularity neither.\n\nMethod is easy. But you need to know about gRPC and its bidirectional connection. Both very simple concepts.\n\nWe create a http server and also a gRPC server. When we have traffic we invoke one or more Lambda functions.\n\nThose Lambda functions create a bidirectional connection to our gRPC server which is running along with http server.\n\nLambda functions wont after one request. They stay to get and serve many requests with sub microsecond delay from now on.\n\nNow http server relays the load to Lambda functions through gRPC and gets the result back.\n\nWe just need a mechanism to invoke enough Lambda function to handle our traffic. And when traffic is low to stop them.\n\nThis repository has one sample implementation to show the concept.\n\n# Tools\n\nSolution does not depend on these, but I picked gRPC as RPC framework and protobuf as data interchange format and Go to implement it.\n\n# Data interchange format\n\nProtobuf is a simple [format](https://developers.google.com/protocol-buffers/docs/proto3).\n\nPayload definition is at `payload/payload.proto`.\n\nIf you are gonna encode/decode your data what is there is enough, otherwise edit `payload.proto` and regenereate the go file.\n\n# Lambda scheduler\n\nTo invoke Lambda function you need to pass the scheduler to `NewJobber`.\n\nI implemented to scheduler.\n\n- goroutine.Goroutine: a dummy scheduler which is there only for test purposes.\n- awslambda.LambdaScheduler: A simple scheduler which can invoke a lambda function to send the jobs to it.\n\n```Go\n\ts := gRPC.NewServer()\n\ttaskMachine = jobber.NewJobber(jobber.Scheduler(\u0026goroutine.Goroutine{GrpcHost: \"localhost:50051\"}))\n\ttaskMachine.RegisterGRPC(s)\n```\n\nScheduler need to implements the following inteface:\n\n```Go\ninterface {\n\t// Inbound is called before a new task is added.\n\tInbound()\n\t// Done is called when a task is done\n\tDone()\n\t// Timedout is called when no response was received on time for a task\n\tTimedout()\n}\n```\n\n![flow](https://kavehmz.github.io/static/images/lambda_for_micro_jobs.png \"Lambda for micro requests\")\n\nThis solution does not depend on protobuf, gRPC or aws lambda but in this implementation I picked those tools,\n\n# Test run\n\n`example` includes a dummy test case and also an example of using lamba scheduler.\n\njust to see how it all works simply do the following\n\nIn one terminal run the example\n```bash\n$go run example/goroutine/main.go \n2018/02/11 14:48:57 Start listening gRPC at 50051\n2018/02/11 14:49:17 minion: job inbound 0 0\n2018/02/11 14:49:17 worker[1]: Hi, I was invoked and I am trying to connect to accept jobs\n2018/02/11 14:49:17 worker[1]: I Joined the workforce\n2018/02/11 14:49:17 server: A new minion joined to help\n2018/02/11 14:49:17 server: got a job\n2018/02/11 14:49:17 worker[1]: received a task from server data:\"This is the payload I will send to Lambda.\" \n2018/02/11 14:49:18 worker[1]: task is done\n2018/02/11 14:49:18 server: received the response\n2018/02/11 14:49:18 server: send the response\n2018/02/11 14:49:18 server: send the response back to client\n2018/02/11 14:49:18 minion: job done\n2018/02/11 14:49:18 Example: received data:\"2018-02-11 14:49:18.623911211 +0100 CET m=+21.589500545\"  \u003cnil\u003e\n```\n\n In another terminal send a request\n```\n$ curl 'http://localhost:8000/'\n2018-02-11 14:49:18.623911211 +0100 CET m=+21.589500545\n```\n\nIn the code, your request goes to http server. Your handler will call Do and wait for response. Managing Lambda functions and sending and receiving message is done by jobber\n\n```go\nresp, err := myJobber.Do(\u0026payload.Task{Data: \"This is the payload I will send to Lambda.\"})\nif err != nil {\n\tresp = \u0026payload.Result{Data: \"Because of error result was returned as nil\"}\n}\nlog.Println(\"Example: received\", resp, err)\nfmt.Fprint(w, resp.Data)\n```\n\n## Test Lambda\nIf you are familiar with Lambda function, setting up one is easy.\n\nBut notice lambda functions need to connect back you the gRPC server which Jobber depends on. So they must be in the same network (VPC), or somehow they need to have access you your gRPC port.\n\nYou can see an example at `example/lambda` and a sample Lambda function which does nothing at `example/aws_func`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkavehmz%2Fjobber","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkavehmz%2Fjobber","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkavehmz%2Fjobber/lists"}