diff --git a/404.html b/404.html index d7e9c97..f1ffa83 100644 --- a/404.html +++ b/404.html @@ -4,7 +4,7 @@ Polaris - + diff --git a/assets/js/64069c70.a622f2a9.js b/assets/js/64069c70.69a864a4.js similarity index 98% rename from assets/js/64069c70.a622f2a9.js rename to assets/js/64069c70.69a864a4.js index 915e1a3..5b7e88a 100644 --- a/assets/js/64069c70.a622f2a9.js +++ b/assets/js/64069c70.69a864a4.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[194],{7197:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>a,toc:()=>l});var s=t(4848),r=t(8453);const i={sidebar_position:3},o="Builder",a={id:"concepts/builder",title:"Builder",description:"An actor that consumes a bunch of data and produces another data. It has the following meta associated with it:",source:"@site/docs/concepts/builder.md",sourceDirName:"concepts",slug:"/concepts/builder",permalink:"/polaris/concepts/builder",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Workflow",permalink:"/polaris/concepts/workflow"},next:{title:"Data",permalink:"/polaris/concepts/data"}},c={},l=[];function d(e){const n={code:"code",h1:"h1",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"builder",children:"Builder"}),"\n",(0,s.jsx)(n.p,{children:"An actor that consumes a bunch of data and produces another data. It has the following meta associated with it:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Name"})," - Name of the builder."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Consumes"})," - A set of data that the builder consumes."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Produces"})," - Data that the builder produces."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Optionals"})," - Data that the builder can optionally consume; one possible use case for this: if a builder wants to be re-run on demand with the same set of consumable data already present, add an optional data in the Builder and restart the workflow by passing an instance of the optional data in the data-delta"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Access"})," - Data that the builder will just access and has no effect on the sequence of execution of builders"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"BuilderContext"})," - A wrapper to access the data given to that builder to process."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["A Builder is a unit of work in the workflow. Builders must implement the ",(0,s.jsx)(n.code,{children:"IBuilder"})," interface."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-go",children:"type IBuilder interface {\n GetBuilderInfo() BuilderInfo\n Process(BuilderContext) IData\n}\n"})}),"\n",(0,s.jsx)(n.p,{children:"Following the same example, for the first unit of work in a cab ride workflow:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-go",children:"var database Database\nvar cabbieHttpClient CabbieHttpClient \n\ntype UserInitiation struct {\n}\n\nfunc (uI UserInitiation) GetBuilderInfo() BuilderInfo {\n return BuilderInfo{\n Consumes: []IData{\n UserInitiationRequest{},\n },\n Produces: UserInitiationResponse{},\n Optionals: nil,\n Accesses: nil,\n }\n}\n\nfunc (uI UserInitiation) Process(context BuilderContext) IData {\n userInitReq := context.get(UserInitiationRequest{})\n // save the request in a database (different from Polaris storing workflows in `IDataStore`)\n database.save(userInitReq)\n\n // call another service to place a request, and wait for the response\n cabbieResponse := cabbieHttpClient.request(RideRequest{\n userId: userInitReq.userId,\n source: userInitReq.source,\n dest: userInitReq.dest\n })\n\n // once done, return the `Produces` of the data\n return UserInitiationResponse{\n success: true,\n etaForCabbie: cabbieResponse.eta\n }\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(6540);const r={},i=s.createContext(r);function o(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[194],{7197:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>a,toc:()=>l});var s=t(4848),r=t(8453);const i={sidebar_position:3},o="Builder",a={id:"concepts/builder",title:"Builder",description:"An actor that consumes a bunch of data and produces another data. It has the following meta associated with it:",source:"@site/docs/concepts/builder.md",sourceDirName:"concepts",slug:"/concepts/builder",permalink:"/polaris/concepts/builder",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Workflow",permalink:"/polaris/concepts/workflow"},next:{title:"Data",permalink:"/polaris/concepts/data"}},c={},l=[];function d(e){const n={code:"code",h1:"h1",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"builder",children:"Builder"}),"\n",(0,s.jsx)(n.p,{children:"An actor that consumes a bunch of data and produces another data. It has the following meta associated with it:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Name"})," - Name of the builder."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Consumes"})," - A set of data that the builder consumes."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Produces"})," - Data that the builder produces."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Optionals"})," - Data that the builder can optionally consume; one possible use case for this: if a builder wants to be re-run on demand with the same set of consumable data already present, add an optional data in the Builder and restart the workflow by passing an instance of the optional data in the data-delta"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Access"})," - Data that the builder will just access and has no effect on the sequence of execution of builders"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"BuilderContext"})," - A wrapper to access the data given to that builder to process."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["A Builder is a unit of work in the workflow. Builders must implement the ",(0,s.jsx)(n.code,{children:"IBuilder"})," interface."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-go",children:"type IBuilder interface {\n GetBuilderInfo() BuilderInfo\n Process(BuilderContext) IData\n}\n"})}),"\n",(0,s.jsx)(n.p,{children:"Following the same example, for the first unit of work in a cab ride workflow:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-go",children:"var database Database\nvar cabbieHttpClient CabbieHttpClient \n\ntype UserInitiation struct {\n}\n\nfunc (uI UserInitiation) GetBuilderInfo() BuilderInfo {\n return BuilderInfo{\n Consumes: []IData{\n UserInitiationRequest{},\n },\n Produces: UserInitiationResponse{},\n Optionals: nil,\n Accesses: nil,\n }\n}\n\nfunc (uI UserInitiation) Process(context BuilderContext) IData {\n userInitReq := context.Get(UserInitiationRequest{})\n // save the request in a database (different from Polaris storing workflows in `IDataStore`)\n database.save(userInitReq)\n\n // call another service to place a request, and wait for the response\n cabbieResponse := cabbieHttpClient.request(RideRequest{\n userId: userInitReq.userId,\n source: userInitReq.source,\n dest: userInitReq.dest\n })\n\n // once done, return the `Produces` of the data\n return UserInitiationResponse{\n success: true,\n etaForCabbie: cabbieResponse.eta\n }\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(6540);const r={},i=s.createContext(r);function o(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6476eba6.3941bb3d.js b/assets/js/6476eba6.dae90a5a.js similarity index 99% rename from assets/js/6476eba6.3941bb3d.js rename to assets/js/6476eba6.dae90a5a.js index d03f7dd..3e1c16e 100644 --- a/assets/js/6476eba6.3941bb3d.js +++ b/assets/js/6476eba6.dae90a5a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[722],{7493:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>i,metadata:()=>a,toc:()=>d});var t=n(4848),o=n(8453);const i={sidebar_position:4},s="Usage",a={id:"usage",title:"Usage",description:"From the root of your Go module, run:",source:"@site/docs/usage.md",sourceDirName:".",slug:"/usage",permalink:"/polaris/usage",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Data Store",permalink:"/polaris/concepts/datastore"},next:{title:"What's next?",permalink:"/polaris/upcoming"}},l={},d=[{value:"Adding Polaris to your Go app",id:"adding-polaris-to-your-go-app",level:2},{value:"Service Startup",id:"service-startup",level:3},{value:"Runtime",id:"runtime",level:3},{value:"Limitations",id:"limitations",level:2},{value:"Workflow versioning",id:"workflow-versioning",level:3},{value:"How does the framework perform at scale?",id:"how-does-the-framework-perform-at-scale",level:2},{value:"Use cases",id:"use-cases",level:2}];function c(e){const r={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.h1,{id:"usage",children:"Usage"}),"\n",(0,t.jsx)(r.p,{children:"From the root of your Go module, run:"}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{children:"go get github.com/harshadmanglani/polaris\n"})}),"\n",(0,t.jsx)(r.h2,{id:"adding-polaris-to-your-go-app",children:"Adding Polaris to your Go app"}),"\n",(0,t.jsxs)(r.p,{children:["Assuming you've already read up on ",(0,t.jsx)("a",{href:"/polaris/concepts/polaris",children:"concepts"}),", let's get started"]}),"\n",(0,t.jsx)(r.p,{children:"We'll break integration in two parts:"}),"\n",(0,t.jsxs)(r.ul,{children:["\n",(0,t.jsx)(r.li,{children:"Things to do when your Go app is starting up"}),"\n",(0,t.jsx)(r.li,{children:"Things to do at runtime"}),"\n"]}),"\n",(0,t.jsx)(r.h3,{id:"service-startup",children:"Service Startup"}),"\n",(0,t.jsx)(r.p,{children:"This is where you want to"}),"\n",(0,t.jsxs)(r.ol,{children:["\n",(0,t.jsxs)(r.li,{children:["Implement the ",(0,t.jsx)("a",{href:"/polaris/concepts/datastore",children:(0,t.jsx)(r.code,{children:"IDataStore"})})," interface and initialize Polaris with it"]}),"\n",(0,t.jsxs)(r.li,{children:["Register your ",(0,t.jsx)("a",{href:"/polaris/concepts/workflow",children:"workflow(s)"})," with Polaris"]}),"\n",(0,t.jsx)(r.li,{children:"Initialize your executor"}),"\n"]}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{className:"language-go",children:'var dataStore polaris.IDataStore\nvar executor polaris.Executor\n\nvoid init(){\n dataStore := SomeDataStoreImpl{}\n polaris.InitRegistry(dataStore)\n\n polaris.RegisterWorkflow("alphaWorkflowKey", AlphaWorkflow{})\n\n executor := polaris.Executor{\n Before: func(builder reflect.Type, delta []IData) {\n fmt.Printf("Builder %s is about to be run with new data %v\\n", builder, delta)\n }\n After: func(builder reflect.Type, produced IData) {\n fmt.Printf("Builder %s produced %s\\n", builder, produced)\n }\n }\n}\n'})}),"\n",(0,t.jsx)(r.h3,{id:"runtime",children:"Runtime"}),"\n",(0,t.jsx)(r.p,{children:"This is where you process requests on your server by handing them over to polaris."}),"\n",(0,t.jsx)(r.p,{children:"At runtime, you must"}),"\n",(0,t.jsxs)(r.ol,{children:["\n",(0,t.jsx)(r.li,{children:"Accept the request"}),"\n",(0,t.jsxs)(r.li,{children:["Generate a unique identifier for this request (",(0,t.jsx)(r.code,{children:"uniqueWorkflowId"}),")"]}),"\n",(0,t.jsxs)(r.li,{children:["Pass your request data (ensuring that it would be part of the ",(0,t.jsx)("a",{href:"/polaris/concepts/builder#:~:text=of%20the%20builder.-,Consumes,-%2D%20A%20set%20of",children:(0,t.jsx)(r.code,{children:"Consumes"})})," for the ",(0,t.jsx)("a",{href:"/polaris/concepts/builder",children:(0,t.jsx)(r.code,{children:"Builder"})})," you want to run)"]}),"\n"]}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{className:"language-go",children:'void main(){\n http.HandleFunc("/request", RequestHandler)\n\n fmt.Println("Server running at port 8080...")\n http.ListenAndServe(":8080", nil)\n}\n\nfunc RequestHandler(w http.ResponseWriter, r *http.Request) {\n var alpha AlphaConsumes\n err := json.NewDecoder(r.Body).Decode(&alpha)\n if err != nil {\n http.Error(w, err.Error(), http.StatusBadRequest)\n return\n }\n\n uniqueWorkflowId := alpha.Id\n result := executor.Sequential("alphaWorkflowKey", uniqueWorkflowId, alpha)\n\n // fetch expected data from the result\n alphaProcessed, ok := result.get(AlphaProcessed{})\n if !ok {\n w.WriteHeader(http.StatusInternalServerError)\n }\n\n // do something with alphaProcessed\n w.WriteHeader(http.StatusOK)\n}\n'})}),"\n",(0,t.jsx)(r.h2,{id:"limitations",children:"Limitations"}),"\n",(0,t.jsx)(r.h3,{id:"workflow-versioning",children:"Workflow versioning"}),"\n",(0,t.jsxs)(r.ol,{children:["\n",(0,t.jsx)(r.li,{children:"Unless you can afford a 100% downtime ensuring all active workflows move into a terminal state, deploying new code requires ensuring backward compatibility."}),"\n",(0,t.jsx)(r.li,{children:"What this means is - you'll need to a deploy a version of code that is backward compatible for older non terminal workflows while newer ones will execute on the new code."}),"\n",(0,t.jsx)(r.li,{children:"Once the older workflows have completed, a deployment to clean up stale code will be required."}),"\n"]}),"\n",(0,t.jsx)(r.h2,{id:"how-does-the-framework-perform-at-scale",children:"How does the framework perform at scale?"}),"\n",(0,t.jsx)(r.p,{children:"The framework itself has extremely low overhead. Since execution graphs are generated pre-runtime, all the orchestrator will do at runtime is use the graph and available data to run whichever builders can be run."}),"\n",(0,t.jsx)(r.h2,{id:"use-cases",children:"Use cases"}),"\n",(0,t.jsxs)(r.ol,{children:["\n",(0,t.jsx)(r.li,{children:"You have multi-step workflow executions where each step is dependent on data generated from previous steps."}),"\n",(0,t.jsx)(r.li,{children:"Executions can span one request scope or multiple scopes."}),"\n",(0,t.jsx)(r.li,{children:"Your systems works with reusable components that can be combined in different ways to generate different end-results."}),"\n",(0,t.jsx)(r.li,{children:"Your workflows can pause, resume or even restart from the beginning."}),"\n"]})]})}function u(e={}){const{wrapper:r}={...(0,o.R)(),...e.components};return r?(0,t.jsx)(r,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,r,n)=>{n.d(r,{R:()=>s,x:()=>a});var t=n(6540);const o={},i=t.createContext(o);function s(e){const r=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function a(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),t.createElement(i.Provider,{value:r},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[722],{7493:(e,r,n)=>{n.r(r),n.d(r,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>i,metadata:()=>a,toc:()=>d});var t=n(4848),o=n(8453);const i={sidebar_position:4},s="Usage",a={id:"usage",title:"Usage",description:"From the root of your Go module, run:",source:"@site/docs/usage.md",sourceDirName:".",slug:"/usage",permalink:"/polaris/usage",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Data Store",permalink:"/polaris/concepts/datastore"},next:{title:"What's next?",permalink:"/polaris/upcoming"}},l={},d=[{value:"Adding Polaris to your Go app",id:"adding-polaris-to-your-go-app",level:2},{value:"Service Startup",id:"service-startup",level:3},{value:"Runtime",id:"runtime",level:3},{value:"Limitations",id:"limitations",level:2},{value:"Workflow versioning",id:"workflow-versioning",level:3},{value:"How does the framework perform at scale?",id:"how-does-the-framework-perform-at-scale",level:2},{value:"Use cases",id:"use-cases",level:2}];function c(e){const r={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.h1,{id:"usage",children:"Usage"}),"\n",(0,t.jsx)(r.p,{children:"From the root of your Go module, run:"}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{children:"go get github.com/harshadmanglani/polaris\n"})}),"\n",(0,t.jsx)(r.h2,{id:"adding-polaris-to-your-go-app",children:"Adding Polaris to your Go app"}),"\n",(0,t.jsxs)(r.p,{children:["Assuming you've already read up on ",(0,t.jsx)("a",{href:"/polaris/concepts/polaris",children:"concepts"}),", let's get started"]}),"\n",(0,t.jsx)(r.p,{children:"We'll break integration in two parts:"}),"\n",(0,t.jsxs)(r.ul,{children:["\n",(0,t.jsx)(r.li,{children:"Things to do when your Go app is starting up"}),"\n",(0,t.jsx)(r.li,{children:"Things to do at runtime"}),"\n"]}),"\n",(0,t.jsx)(r.h3,{id:"service-startup",children:"Service Startup"}),"\n",(0,t.jsx)(r.p,{children:"This is where you want to"}),"\n",(0,t.jsxs)(r.ol,{children:["\n",(0,t.jsxs)(r.li,{children:["Implement the ",(0,t.jsx)("a",{href:"/polaris/concepts/datastore",children:(0,t.jsx)(r.code,{children:"IDataStore"})})," interface and initialize Polaris with it"]}),"\n",(0,t.jsxs)(r.li,{children:["Register your ",(0,t.jsx)("a",{href:"/polaris/concepts/workflow",children:"workflow(s)"})," with Polaris"]}),"\n",(0,t.jsx)(r.li,{children:"Initialize your executor"}),"\n"]}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{className:"language-go",children:'var dataStore polaris.IDataStore\nvar executor polaris.Executor\n\nvoid init(){\n dataStore := SomeDataStoreImpl{}\n polaris.InitRegistry(dataStore)\n\n polaris.RegisterWorkflow("alphaWorkflowKey", AlphaWorkflow{})\n\n executor := polaris.Executor{\n Before: func(builder reflect.Type, delta []IData) {\n fmt.Printf("Builder %s is about to be run with new data %v\\n", builder, delta)\n }\n After: func(builder reflect.Type, produced IData) {\n fmt.Printf("Builder %s produced %s\\n", builder, produced)\n }\n }\n}\n'})}),"\n",(0,t.jsx)(r.h3,{id:"runtime",children:"Runtime"}),"\n",(0,t.jsx)(r.p,{children:"This is where you process requests on your server by handing them over to polaris."}),"\n",(0,t.jsx)(r.p,{children:"At runtime, you must"}),"\n",(0,t.jsxs)(r.ol,{children:["\n",(0,t.jsx)(r.li,{children:"Accept the request"}),"\n",(0,t.jsxs)(r.li,{children:["Generate a unique identifier for this request (",(0,t.jsx)(r.code,{children:"uniqueWorkflowId"}),")"]}),"\n",(0,t.jsxs)(r.li,{children:["Pass your request data (ensuring that it would be part of the ",(0,t.jsx)("a",{href:"/polaris/concepts/builder#:~:text=of%20the%20builder.-,Consumes,-%2D%20A%20set%20of",children:(0,t.jsx)(r.code,{children:"Consumes"})})," for the ",(0,t.jsx)("a",{href:"/polaris/concepts/builder",children:(0,t.jsx)(r.code,{children:"Builder"})})," you want to run)"]}),"\n"]}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{className:"language-go",children:'void main(){\n http.HandleFunc("/request", RequestHandler)\n\n fmt.Println("Server running at port 8080...")\n http.ListenAndServe(":8080", nil)\n}\n\nfunc RequestHandler(w http.ResponseWriter, r *http.Request) {\n var alpha AlphaConsumes\n err := json.NewDecoder(r.Body).Decode(&alpha)\n if err != nil {\n http.Error(w, err.Error(), http.StatusBadRequest)\n return\n }\n\n uniqueWorkflowId := alpha.Id\n result := executor.Sequential("alphaWorkflowKey", uniqueWorkflowId, alpha)\n\n // fetch expected data from the result\n alphaProcessed, ok := result.Get(AlphaProcessed{})\n if !ok {\n w.WriteHeader(http.StatusInternalServerError)\n }\n\n // do something with alphaProcessed\n w.WriteHeader(http.StatusOK)\n}\n'})}),"\n",(0,t.jsx)(r.h2,{id:"limitations",children:"Limitations"}),"\n",(0,t.jsx)(r.h3,{id:"workflow-versioning",children:"Workflow versioning"}),"\n",(0,t.jsxs)(r.ol,{children:["\n",(0,t.jsx)(r.li,{children:"Unless you can afford a 100% downtime ensuring all active workflows move into a terminal state, deploying new code requires ensuring backward compatibility."}),"\n",(0,t.jsx)(r.li,{children:"What this means is - you'll need to a deploy a version of code that is backward compatible for older non terminal workflows while newer ones will execute on the new code."}),"\n",(0,t.jsx)(r.li,{children:"Once the older workflows have completed, a deployment to clean up stale code will be required."}),"\n"]}),"\n",(0,t.jsx)(r.h2,{id:"how-does-the-framework-perform-at-scale",children:"How does the framework perform at scale?"}),"\n",(0,t.jsx)(r.p,{children:"The framework itself has extremely low overhead. Since execution graphs are generated pre-runtime, all the orchestrator will do at runtime is use the graph and available data to run whichever builders can be run."}),"\n",(0,t.jsx)(r.h2,{id:"use-cases",children:"Use cases"}),"\n",(0,t.jsxs)(r.ol,{children:["\n",(0,t.jsx)(r.li,{children:"You have multi-step workflow executions where each step is dependent on data generated from previous steps."}),"\n",(0,t.jsx)(r.li,{children:"Executions can span one request scope or multiple scopes."}),"\n",(0,t.jsx)(r.li,{children:"Your systems works with reusable components that can be combined in different ways to generate different end-results."}),"\n",(0,t.jsx)(r.li,{children:"Your workflows can pause, resume or even restart from the beginning."}),"\n"]})]})}function u(e={}){const{wrapper:r}={...(0,o.R)(),...e.components};return r?(0,t.jsx)(r,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,r,n)=>{n.d(r,{R:()=>s,x:()=>a});var t=n(6540);const o={},i=t.createContext(o);function s(e){const r=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function a(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),t.createElement(i.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.b15b4919.js b/assets/js/runtime~main.d461af8b.js similarity index 51% rename from assets/js/runtime~main.b15b4919.js rename to assets/js/runtime~main.d461af8b.js index 363b7f8..3874a1a 100644 --- a/assets/js/runtime~main.b15b4919.js +++ b/assets/js/runtime~main.d461af8b.js @@ -1 +1 @@ -(()=>{"use strict";var e,t,r,a,o,c={},n={};function f(e){var t=n[e];if(void 0!==t)return t.exports;var r=n[e]={id:e,loaded:!1,exports:{}};return c[e].call(r.exports,r,r.exports,f),r.loaded=!0,r.exports}f.m=c,f.c=n,e=[],f.O=(t,r,a,o)=>{if(!r){var c=1/0;for(u=0;u=o)&&Object.keys(f.O).every((e=>f.O[e](r[d])))?r.splice(d--,1):(n=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[r,a,o]},f.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return f.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,f.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var o=Object.create(null);f.r(o);var c={};t=t||[null,r({}),r([]),r(r)];for(var n=2&a&&e;"object"==typeof n&&!~t.indexOf(n);n=r(n))Object.getOwnPropertyNames(n).forEach((t=>c[t]=()=>e[t]));return c.default=()=>e,f.d(o,c),o},f.d=(e,t)=>{for(var r in t)f.o(t,r)&&!f.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},f.f={},f.e=e=>Promise.all(Object.keys(f.f).reduce(((t,r)=>(f.f[r](e,t),t)),[])),f.u=e=>"assets/js/"+({27:"287b169c",48:"a94703ab",61:"1f391b9e",95:"b6ccdf79",98:"a7bd4aaa",134:"393be207",151:"55960ee5",194:"64069c70",279:"3d9c95a4",372:"74661bf9",401:"17896441",432:"cd3b6371",439:"657994e7",520:"539cc341",581:"935f2afb",647:"5e95c892",660:"df203c0f",722:"6476eba6",733:"76cfcda4",787:"3720c009",888:"985140cc",906:"7485ae2a"}[e]||e)+"."+{27:"9216d089",48:"8b0ccadb",61:"85901a5d",95:"41686914",98:"fd305e17",134:"286f48df",151:"01c67cf9",194:"a622f2a9",237:"7663bed8",279:"cd9d6053",372:"0c492acc",401:"aafac81f",432:"680a1096",439:"695ebbcd",520:"84ed9ca8",581:"73c3af5b",647:"1dd55255",660:"3f0f3c3f",674:"8da1d51b",722:"3941bb3d",733:"69ca5f27",787:"230bc0c4",888:"eeebafbf",906:"079aa895"}[e]+".js",f.miniCssF=e=>{},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},o="docs:",f.l=(e,t,r,c)=>{if(a[e])a[e].push(t);else{var n,d;if(void 0!==r)for(var i=document.getElementsByTagName("script"),u=0;u{n.onerror=n.onload=null,clearTimeout(s);var o=a[e];if(delete a[e],n.parentNode&&n.parentNode.removeChild(n),o&&o.forEach((e=>e(r))),t)return t(r)},s=setTimeout(b.bind(null,void 0,{type:"timeout",target:n}),12e4);n.onerror=b.bind(null,n.onerror),n.onload=b.bind(null,n.onload),d&&document.head.appendChild(n)}},f.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.p="/polaris/",f.gca=function(e){return e={17896441:"401","287b169c":"27",a94703ab:"48","1f391b9e":"61",b6ccdf79:"95",a7bd4aaa:"98","393be207":"134","55960ee5":"151","64069c70":"194","3d9c95a4":"279","74661bf9":"372",cd3b6371:"432","657994e7":"439","539cc341":"520","935f2afb":"581","5e95c892":"647",df203c0f:"660","6476eba6":"722","76cfcda4":"733","3720c009":"787","985140cc":"888","7485ae2a":"906"}[e]||e,f.p+f.u(e)},(()=>{var e={354:0,869:0};f.f.j=(t,r)=>{var a=f.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(354|869)$/.test(t))e[t]=0;else{var o=new Promise(((r,o)=>a=e[t]=[r,o]));r.push(a[2]=o);var c=f.p+f.u(t),n=new Error;f.l(c,(r=>{if(f.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var o=r&&("load"===r.type?"missing":r.type),c=r&&r.target&&r.target.src;n.message="Loading chunk "+t+" failed.\n("+o+": "+c+")",n.name="ChunkLoadError",n.type=o,n.request=c,a[1](n)}}),"chunk-"+t,t)}},f.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,c=r[0],n=r[1],d=r[2],i=0;if(c.some((t=>0!==e[t]))){for(a in n)f.o(n,a)&&(f.m[a]=n[a]);if(d)var u=d(f)}for(t&&t(r);i{"use strict";var e,t,r,a,o,c={},n={};function d(e){var t=n[e];if(void 0!==t)return t.exports;var r=n[e]={id:e,loaded:!1,exports:{}};return c[e].call(r.exports,r,r.exports,d),r.loaded=!0,r.exports}d.m=c,d.c=n,e=[],d.O=(t,r,a,o)=>{if(!r){var c=1/0;for(u=0;u=o)&&Object.keys(d.O).every((e=>d.O[e](r[f])))?r.splice(f--,1):(n=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[r,a,o]},d.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return d.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var o=Object.create(null);d.r(o);var c={};t=t||[null,r({}),r([]),r(r)];for(var n=2&a&&e;"object"==typeof n&&!~t.indexOf(n);n=r(n))Object.getOwnPropertyNames(n).forEach((t=>c[t]=()=>e[t]));return c.default=()=>e,d.d(o,c),o},d.d=(e,t)=>{for(var r in t)d.o(t,r)&&!d.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((t,r)=>(d.f[r](e,t),t)),[])),d.u=e=>"assets/js/"+({27:"287b169c",48:"a94703ab",61:"1f391b9e",95:"b6ccdf79",98:"a7bd4aaa",134:"393be207",151:"55960ee5",194:"64069c70",279:"3d9c95a4",372:"74661bf9",401:"17896441",432:"cd3b6371",439:"657994e7",520:"539cc341",581:"935f2afb",647:"5e95c892",660:"df203c0f",722:"6476eba6",733:"76cfcda4",787:"3720c009",888:"985140cc",906:"7485ae2a"}[e]||e)+"."+{27:"9216d089",48:"8b0ccadb",61:"85901a5d",95:"41686914",98:"fd305e17",134:"286f48df",151:"01c67cf9",194:"69a864a4",237:"7663bed8",279:"cd9d6053",372:"0c492acc",401:"aafac81f",432:"680a1096",439:"695ebbcd",520:"84ed9ca8",581:"73c3af5b",647:"1dd55255",660:"3f0f3c3f",674:"8da1d51b",722:"dae90a5a",733:"69ca5f27",787:"230bc0c4",888:"eeebafbf",906:"079aa895"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},o="docs:",d.l=(e,t,r,c)=>{if(a[e])a[e].push(t);else{var n,f;if(void 0!==r)for(var i=document.getElementsByTagName("script"),u=0;u{n.onerror=n.onload=null,clearTimeout(s);var o=a[e];if(delete a[e],n.parentNode&&n.parentNode.removeChild(n),o&&o.forEach((e=>e(r))),t)return t(r)},s=setTimeout(b.bind(null,void 0,{type:"timeout",target:n}),12e4);n.onerror=b.bind(null,n.onerror),n.onload=b.bind(null,n.onload),f&&document.head.appendChild(n)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/polaris/",d.gca=function(e){return e={17896441:"401","287b169c":"27",a94703ab:"48","1f391b9e":"61",b6ccdf79:"95",a7bd4aaa:"98","393be207":"134","55960ee5":"151","64069c70":"194","3d9c95a4":"279","74661bf9":"372",cd3b6371:"432","657994e7":"439","539cc341":"520","935f2afb":"581","5e95c892":"647",df203c0f:"660","6476eba6":"722","76cfcda4":"733","3720c009":"787","985140cc":"888","7485ae2a":"906"}[e]||e,d.p+d.u(e)},(()=>{var e={354:0,869:0};d.f.j=(t,r)=>{var a=d.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(354|869)$/.test(t))e[t]=0;else{var o=new Promise(((r,o)=>a=e[t]=[r,o]));r.push(a[2]=o);var c=d.p+d.u(t),n=new Error;d.l(c,(r=>{if(d.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var o=r&&("load"===r.type?"missing":r.type),c=r&&r.target&&r.target.src;n.message="Loading chunk "+t+" failed.\n("+o+": "+c+")",n.name="ChunkLoadError",n.type=o,n.request=c,a[1](n)}}),"chunk-"+t,t)}},d.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,c=r[0],n=r[1],f=r[2],i=0;if(c.some((t=>0!==e[t]))){for(a in n)d.o(n,a)&&(d.m[a]=n[a]);if(f)var u=f(d)}for(t&&t(r);i Builder | Polaris - + @@ -21,6 +21,6 @@

A Builder is a unit of work in the workflow. Builders must implement the IBuilder interface.

type IBuilder interface {
GetBuilderInfo() BuilderInfo
Process(BuilderContext) IData
}

Following the same example, for the first unit of work in a cab ride workflow:

-
var database Database
var cabbieHttpClient CabbieHttpClient

type UserInitiation struct {
}

func (uI UserInitiation) GetBuilderInfo() BuilderInfo {
return BuilderInfo{
Consumes: []IData{
UserInitiationRequest{},
},
Produces: UserInitiationResponse{},
Optionals: nil,
Accesses: nil,
}
}

func (uI UserInitiation) Process(context BuilderContext) IData {
userInitReq := context.get(UserInitiationRequest{})
// save the request in a database (different from Polaris storing workflows in `IDataStore`)
database.save(userInitReq)

// call another service to place a request, and wait for the response
cabbieResponse := cabbieHttpClient.request(RideRequest{
userId: userInitReq.userId,
source: userInitReq.source,
dest: userInitReq.dest
})

// once done, return the `Produces` of the data
return UserInitiationResponse{
success: true,
etaForCabbie: cabbieResponse.eta
}
}
+
var database Database
var cabbieHttpClient CabbieHttpClient

type UserInitiation struct {
}

func (uI UserInitiation) GetBuilderInfo() BuilderInfo {
return BuilderInfo{
Consumes: []IData{
UserInitiationRequest{},
},
Produces: UserInitiationResponse{},
Optionals: nil,
Accesses: nil,
}
}

func (uI UserInitiation) Process(context BuilderContext) IData {
userInitReq := context.Get(UserInitiationRequest{})
// save the request in a database (different from Polaris storing workflows in `IDataStore`)
database.save(userInitReq)

// call another service to place a request, and wait for the response
cabbieResponse := cabbieHttpClient.request(RideRequest{
userId: userInitReq.userId,
source: userInitReq.source,
dest: userInitReq.dest
})

// once done, return the `Produces` of the data
return UserInitiationResponse{
success: true,
etaForCabbie: cabbieResponse.eta
}
}
\ No newline at end of file diff --git a/concepts/data.html b/concepts/data.html index 77ca48f..70c02ca 100644 --- a/concepts/data.html +++ b/concepts/data.html @@ -4,7 +4,7 @@ Data | Polaris - + diff --git a/concepts/datastore.html b/concepts/datastore.html index 9c2cfa9..1ee2354 100644 --- a/concepts/datastore.html +++ b/concepts/datastore.html @@ -4,7 +4,7 @@ Data Store | Polaris - + diff --git a/concepts/polaris.html b/concepts/polaris.html index 09e9f3a..ae36a54 100644 --- a/concepts/polaris.html +++ b/concepts/polaris.html @@ -4,7 +4,7 @@ Polaris | Polaris - + diff --git a/concepts/workflow.html b/concepts/workflow.html index 0254f05..7ade53d 100644 --- a/concepts/workflow.html +++ b/concepts/workflow.html @@ -4,7 +4,7 @@ Workflow | Polaris - + diff --git a/get-started.html b/get-started.html index d363e59..a1b1804 100644 --- a/get-started.html +++ b/get-started.html @@ -4,7 +4,7 @@ Get Started | Polaris - + diff --git a/index.html b/index.html index 83d9231..9793655 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ Home | Polaris - + diff --git a/markdown-page.html b/markdown-page.html index 430d5de..74ef096 100644 --- a/markdown-page.html +++ b/markdown-page.html @@ -4,7 +4,7 @@ Markdown page example | Polaris - + diff --git a/tags.html b/tags.html index 1c3d394..7129e9f 100644 --- a/tags.html +++ b/tags.html @@ -4,7 +4,7 @@ Tags | Polaris - + diff --git a/tags/go.html b/tags/go.html index 1598cbf..a8bbc71 100644 --- a/tags/go.html +++ b/tags/go.html @@ -4,7 +4,7 @@ One doc tagged with "go" | Polaris - + diff --git a/upcoming.html b/upcoming.html index f388a32..15a55a5 100644 --- a/upcoming.html +++ b/upcoming.html @@ -4,7 +4,7 @@ What's next? | Polaris - + diff --git a/usage.html b/usage.html index e6aeb30..f3d9e1a 100644 --- a/usage.html +++ b/usage.html @@ -4,7 +4,7 @@ Usage | Polaris - + @@ -34,7 +34,7 @@

RuntimeConsumes for the Builder you want to run) -
void main(){
http.HandleFunc("/request", RequestHandler)

fmt.Println("Server running at port 8080...")
http.ListenAndServe(":8080", nil)
}

func RequestHandler(w http.ResponseWriter, r *http.Request) {
var alpha AlphaConsumes
err := json.NewDecoder(r.Body).Decode(&alpha)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

uniqueWorkflowId := alpha.Id
result := executor.Sequential("alphaWorkflowKey", uniqueWorkflowId, alpha)

// fetch expected data from the result
alphaProcessed, ok := result.get(AlphaProcessed{})
if !ok {
w.WriteHeader(http.StatusInternalServerError)
}

// do something with alphaProcessed
w.WriteHeader(http.StatusOK)
}
+
void main(){
http.HandleFunc("/request", RequestHandler)

fmt.Println("Server running at port 8080...")
http.ListenAndServe(":8080", nil)
}

func RequestHandler(w http.ResponseWriter, r *http.Request) {
var alpha AlphaConsumes
err := json.NewDecoder(r.Body).Decode(&alpha)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

uniqueWorkflowId := alpha.Id
result := executor.Sequential("alphaWorkflowKey", uniqueWorkflowId, alpha)

// fetch expected data from the result
alphaProcessed, ok := result.Get(AlphaProcessed{})
if !ok {
w.WriteHeader(http.StatusInternalServerError)
}

// do something with alphaProcessed
w.WriteHeader(http.StatusOK)
}

Limitations

Workflow versioning