├── .gitignore ├── .vscode └── launch.json ├── ASync ├── readme.md └── src │ └── Azure │ └── JS │ ├── .gitignore │ ├── .vscode │ └── launch.json │ ├── ASyncMng │ └── index.js │ ├── HeroesApiDelete │ ├── function.json │ ├── index.js │ └── sample.dat │ ├── HeroesApiGet │ ├── function.json │ ├── index.js │ └── sample.dat │ ├── HeroesApiPost │ ├── function.json │ ├── index.js │ └── sample.dat │ ├── HeroesApiStatus │ ├── function.json │ ├── index.js │ └── sample.dat │ ├── HeroesApiUpdate │ ├── function.json │ ├── index.js │ └── sample.dat │ ├── HerosAsyncDoWork │ ├── function.json │ ├── index.js │ └── sample.dat │ ├── TriggerFunc │ ├── function.json │ ├── index.js │ └── sample.dat │ ├── heroes │ └── index.js │ ├── host.json │ └── package.json ├── Docs └── Images │ └── functionChain_1.JPG ├── FunctionsChaining ├── readme.md └── src │ └── Azure │ └── JS │ ├── .gitignore │ ├── .vscode │ └── launch.json │ ├── Func1 │ ├── function.json │ ├── index.js │ ├── readme.md │ └── sample.dat │ ├── Func2 │ ├── function.json │ ├── index.js │ ├── readme.md │ └── sample.dat │ ├── Func3 │ ├── function.json │ ├── index.js │ ├── readme.md │ └── sample.dat │ ├── TriggerFunc │ ├── function.json │ ├── index.js │ └── sample.dat │ └── host.json ├── FunctionsChainingTransaction ├── readme.md └── src │ └── Azure │ └── JS │ ├── .gitignore │ ├── .vscode │ └── launch.json │ ├── ChainQMsg │ └── index.js │ ├── Func1 │ ├── function.json │ ├── index.js │ ├── readme.md │ └── sample.dat │ ├── Func2 │ ├── function.json │ ├── index.js │ ├── readme.md │ └── sample.dat │ ├── Func3 │ ├── function.json │ ├── index.js │ ├── readme.md │ └── sample.dat │ ├── TriggerFunc │ ├── function.json │ ├── index.js │ └── sample.dat │ ├── host.json │ └── package.json └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,windows,visualstudio,visualstudiocode 3 | 4 | ### OSX ### 5 | *.DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | 13 | # Thumbnails 14 | ._* 15 | 16 | # Files that might appear in the root of a volume 17 | .DocumentRevisions-V100 18 | .fseventsd 19 | .Spotlight-V100 20 | .TemporaryItems 21 | .Trashes 22 | .VolumeIcon.icns 23 | .com.apple.timemachine.donotpresent 24 | 25 | # Directories potentially created on remote AFP share 26 | .AppleDB 27 | .AppleDesktop 28 | Network Trash Folder 29 | Temporary Items 30 | .apdisk 31 | 32 | ### VisualStudioCode ### 33 | .vscode/* 34 | !.vscode/settings.json 35 | !.vscode/tasks.json 36 | !.vscode/launch.json 37 | !.vscode/extensions.json 38 | 39 | ### Windows ### 40 | # Windows thumbnail cache files 41 | Thumbs.db 42 | ehthumbs.db 43 | ehthumbs_vista.db 44 | 45 | # Folder config file 46 | Desktop.ini 47 | 48 | # Recycle Bin used on file shares 49 | $RECYCLE.BIN/ 50 | 51 | # Windows Installer files 52 | *.cab 53 | *.msi 54 | *.msm 55 | *.msp 56 | 57 | # Windows shortcuts 58 | *.lnk 59 | 60 | ### VisualStudio ### 61 | ## Ignore Visual Studio temporary files, build results, and 62 | ## files generated by popular Visual Studio add-ons. 63 | ## 64 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 65 | 66 | # User-specific files 67 | *.suo 68 | *.user 69 | *.userosscache 70 | *.sln.docstates 71 | 72 | # User-specific files (MonoDevelop/Xamarin Studio) 73 | *.userprefs 74 | 75 | # Build results 76 | [Dd]ebug/ 77 | [Dd]ebugPublic/ 78 | [Rr]elease/ 79 | [Rr]eleases/ 80 | x64/ 81 | x86/ 82 | bld/ 83 | [Bb]in/ 84 | [Oo]bj/ 85 | [Ll]og/ 86 | 87 | # Visual Studio 2015 cache/options directory 88 | .vs/ 89 | # Uncomment if you have tasks that create the project's static files in wwwroot 90 | #wwwroot/ 91 | 92 | # Azure Functions 93 | project.lock.json 94 | **/appsettings.json 95 | 96 | # MSTest test Results 97 | [Tt]est[Rr]esult*/ 98 | [Bb]uild[Ll]og.* 99 | 100 | # NUNIT 101 | *.VisualState.xml 102 | TestResult.xml 103 | 104 | # Build Results of an ATL Project 105 | [Dd]ebugPS/ 106 | [Rr]eleasePS/ 107 | dlldata.c 108 | 109 | # .NET Core 110 | project.lock.json 111 | project.fragment.lock.json 112 | artifacts/ 113 | **/Properties/launchSettings.json 114 | 115 | *_i.c 116 | *_p.c 117 | *_i.h 118 | *.ilk 119 | *.meta 120 | *.obj 121 | *.pch 122 | *.pdb 123 | *.pgc 124 | *.pgd 125 | *.rsp 126 | *.sbr 127 | *.tlb 128 | *.tli 129 | *.tlh 130 | *.tmp 131 | *.tmp_proj 132 | *.log 133 | *.vspscc 134 | *.vssscc 135 | .builds 136 | *.pidb 137 | *.svclog 138 | *.scc 139 | 140 | # Chutzpah Test files 141 | _Chutzpah* 142 | 143 | # Visual C++ cache files 144 | ipch/ 145 | *.aps 146 | *.ncb 147 | *.opendb 148 | *.opensdf 149 | *.sdf 150 | *.cachefile 151 | *.VC.db 152 | *.VC.VC.opendb 153 | 154 | # Visual Studio profiler 155 | *.psess 156 | *.vsp 157 | *.vspx 158 | *.sap 159 | 160 | # TFS 2012 Local Workspace 161 | $tf/ 162 | 163 | # Guidance Automation Toolkit 164 | *.gpState 165 | 166 | # ReSharper is a .NET coding add-in 167 | _ReSharper*/ 168 | *.[Rr]e[Ss]harper 169 | *.DotSettings.user 170 | 171 | # JustCode is a .NET coding add-in 172 | .JustCode 173 | 174 | # TeamCity is a build add-in 175 | _TeamCity* 176 | 177 | # DotCover is a Code Coverage Tool 178 | *.dotCover 179 | 180 | # Visual Studio code coverage results 181 | *.coverage 182 | *.coveragexml 183 | 184 | # NCrunch 185 | _NCrunch_* 186 | .*crunch*.local.xml 187 | nCrunchTemp_* 188 | 189 | # MightyMoose 190 | *.mm.* 191 | AutoTest.Net/ 192 | 193 | # Web workbench (sass) 194 | .sass-cache/ 195 | 196 | # Installshield output folder 197 | [Ee]xpress/ 198 | 199 | # DocProject is a documentation generator add-in 200 | DocProject/buildhelp/ 201 | DocProject/Help/*.HxT 202 | DocProject/Help/*.HxC 203 | DocProject/Help/*.hhc 204 | DocProject/Help/*.hhk 205 | DocProject/Help/*.hhp 206 | DocProject/Help/Html2 207 | DocProject/Help/html 208 | 209 | # Click-Once directory 210 | publish/ 211 | 212 | # Publish Web Output 213 | *.[Pp]ublish.xml 214 | *.azurePubxml 215 | # TODO: Comment the next line if you want to checkin your web deploy settings 216 | # but database connection strings (with potential passwords) will be unencrypted 217 | *.pubxml 218 | *.publishproj 219 | 220 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 221 | # checkin your Azure Web App publish settings, but sensitive information contained 222 | # in these scripts will be unencrypted 223 | PublishScripts/ 224 | 225 | # NuGet Packages 226 | *.nupkg 227 | # The packages folder can be ignored because of Package Restore 228 | **/packages/* 229 | # except build/, which is used as an MSBuild target. 230 | !**/packages/build/ 231 | # Uncomment if necessary however generally it will be regenerated when needed 232 | #!**/packages/repositories.config 233 | # NuGet v3's project.json files produces more ignorable files 234 | *.nuget.props 235 | *.nuget.targets 236 | 237 | # Microsoft Azure Build Output 238 | csx/ 239 | *.build.csdef 240 | 241 | # Microsoft Azure Emulator 242 | ecf/ 243 | rcf/ 244 | 245 | # Windows Store app package directories and files 246 | AppPackages/ 247 | BundleArtifacts/ 248 | Package.StoreAssociation.xml 249 | _pkginfo.txt 250 | 251 | # Visual Studio cache files 252 | # files ending in .cache can be ignored 253 | *.[Cc]ache 254 | # but keep track of directories ending in .cache 255 | !*.[Cc]ache/ 256 | 257 | # Others 258 | ClientBin/ 259 | ~$* 260 | *~ 261 | *.dbmdl 262 | *.dbproj.schemaview 263 | *.jfm 264 | *.pfx 265 | *.publishsettings 266 | orleans.codegen.cs 267 | 268 | # Since there are multiple workflows, uncomment next line to ignore bower_components 269 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 270 | #bower_components/ 271 | 272 | # RIA/Silverlight projects 273 | Generated_Code/ 274 | 275 | # Backup & report files from converting an old project file 276 | # to a newer Visual Studio version. Backup files are not needed, 277 | # because we have git ;-) 278 | _UpgradeReport_Files/ 279 | Backup*/ 280 | UpgradeLog*.XML 281 | UpgradeLog*.htm 282 | 283 | # SQL Server files 284 | *.mdf 285 | *.ldf 286 | *.ndf 287 | 288 | # Business Intelligence projects 289 | *.rdl.data 290 | *.bim.layout 291 | *.bim_*.settings 292 | 293 | # Microsoft Fakes 294 | FakesAssemblies/ 295 | 296 | # GhostDoc plugin setting file 297 | *.GhostDoc.xml 298 | 299 | # Node.js Tools for Visual Studio 300 | .ntvs_analysis.dat 301 | node_modules/ 302 | 303 | # Typescript v1 declaration files 304 | typings/ 305 | 306 | # Visual Studio 6 build log 307 | *.plg 308 | 309 | # Visual Studio 6 workspace options file 310 | *.opt 311 | 312 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 313 | *.vbw 314 | 315 | # Visual Studio LightSwitch build output 316 | **/*.HTMLClient/GeneratedArtifacts 317 | **/*.DesktopClient/GeneratedArtifacts 318 | **/*.DesktopClient/ModelManifest.xml 319 | **/*.Server/GeneratedArtifacts 320 | **/*.Server/ModelManifest.xml 321 | _Pvt_Extensions 322 | 323 | # Paket dependency manager 324 | .paket/paket.exe 325 | paket-files/ 326 | 327 | # FAKE - F# Make 328 | .fake/ 329 | 330 | # JetBrains Rider 331 | .idea/ 332 | *.sln.iml 333 | 334 | # CodeRush 335 | .cr/ 336 | 337 | # Python Tools for Visual Studio (PTVS) 338 | __pycache__/ 339 | *.pyc 340 | 341 | # Cake - Uncomment if you are using it 342 | # tools/** 343 | # !tools/packages.config 344 | 345 | # Telerik's JustMock configuration file 346 | *.jmconfig 347 | 348 | # BizTalk build output 349 | *.btp.cs 350 | *.btm.cs 351 | *.odx.cs 352 | *.xsd.cs 353 | 354 | # End of https://www.gitignore.io/api/osx,windows,visualstudio,visualstudiocode -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${file}" 12 | }, 13 | { 14 | "type": "node", 15 | "request": "attach", 16 | "name": "Attach to Port", 17 | "address": "localhost", 18 | "port": 5858 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /ASync/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yochay/serverlesspatterns/352052fdc76348c4285cd3094ca113a021e82236/ASync/readme.md -------------------------------------------------------------------------------- /ASync/src/Azure/JS/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,windows,visualstudio,visualstudiocode 3 | 4 | ### OSX ### 5 | *.DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | 13 | # Thumbnails 14 | ._* 15 | 16 | # Files that might appear in the root of a volume 17 | .DocumentRevisions-V100 18 | .fseventsd 19 | .Spotlight-V100 20 | .TemporaryItems 21 | .Trashes 22 | .VolumeIcon.icns 23 | .com.apple.timemachine.donotpresent 24 | 25 | # Directories potentially created on remote AFP share 26 | .AppleDB 27 | .AppleDesktop 28 | Network Trash Folder 29 | Temporary Items 30 | .apdisk 31 | 32 | ### VisualStudioCode ### 33 | .vscode/* 34 | !.vscode/settings.json 35 | !.vscode/tasks.json 36 | !.vscode/launch.json 37 | !.vscode/extensions.json 38 | 39 | ### Windows ### 40 | # Windows thumbnail cache files 41 | Thumbs.db 42 | ehthumbs.db 43 | ehthumbs_vista.db 44 | 45 | # Folder config file 46 | Desktop.ini 47 | 48 | # Recycle Bin used on file shares 49 | $RECYCLE.BIN/ 50 | 51 | # Windows Installer files 52 | *.cab 53 | *.msi 54 | *.msm 55 | *.msp 56 | 57 | # Windows shortcuts 58 | *.lnk 59 | 60 | ### VisualStudio ### 61 | ## Ignore Visual Studio temporary files, build results, and 62 | ## files generated by popular Visual Studio add-ons. 63 | ## 64 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 65 | 66 | # User-specific files 67 | *.suo 68 | *.user 69 | *.userosscache 70 | *.sln.docstates 71 | 72 | # User-specific files (MonoDevelop/Xamarin Studio) 73 | *.userprefs 74 | 75 | # Build results 76 | [Dd]ebug/ 77 | [Dd]ebugPublic/ 78 | [Rr]elease/ 79 | [Rr]eleases/ 80 | x64/ 81 | x86/ 82 | bld/ 83 | [Bb]in/ 84 | [Oo]bj/ 85 | [Ll]og/ 86 | 87 | # Visual Studio 2015 cache/options directory 88 | .vs/ 89 | # Uncomment if you have tasks that create the project's static files in wwwroot 90 | #wwwroot/ 91 | 92 | # Azure Functions 93 | project.lock.json 94 | appsetting.json 95 | 96 | # MSTest test Results 97 | [Tt]est[Rr]esult*/ 98 | [Bb]uild[Ll]og.* 99 | 100 | # NUNIT 101 | *.VisualState.xml 102 | TestResult.xml 103 | 104 | # Build Results of an ATL Project 105 | [Dd]ebugPS/ 106 | [Rr]eleasePS/ 107 | dlldata.c 108 | 109 | # .NET Core 110 | project.lock.json 111 | project.fragment.lock.json 112 | artifacts/ 113 | **/Properties/launchSettings.json 114 | 115 | *_i.c 116 | *_p.c 117 | *_i.h 118 | *.ilk 119 | *.meta 120 | *.obj 121 | *.pch 122 | *.pdb 123 | *.pgc 124 | *.pgd 125 | *.rsp 126 | *.sbr 127 | *.tlb 128 | *.tli 129 | *.tlh 130 | *.tmp 131 | *.tmp_proj 132 | *.log 133 | *.vspscc 134 | *.vssscc 135 | .builds 136 | *.pidb 137 | *.svclog 138 | *.scc 139 | 140 | # Chutzpah Test files 141 | _Chutzpah* 142 | 143 | # Visual C++ cache files 144 | ipch/ 145 | *.aps 146 | *.ncb 147 | *.opendb 148 | *.opensdf 149 | *.sdf 150 | *.cachefile 151 | *.VC.db 152 | *.VC.VC.opendb 153 | 154 | # Visual Studio profiler 155 | *.psess 156 | *.vsp 157 | *.vspx 158 | *.sap 159 | 160 | # TFS 2012 Local Workspace 161 | $tf/ 162 | 163 | # Guidance Automation Toolkit 164 | *.gpState 165 | 166 | # ReSharper is a .NET coding add-in 167 | _ReSharper*/ 168 | *.[Rr]e[Ss]harper 169 | *.DotSettings.user 170 | 171 | # JustCode is a .NET coding add-in 172 | .JustCode 173 | 174 | # TeamCity is a build add-in 175 | _TeamCity* 176 | 177 | # DotCover is a Code Coverage Tool 178 | *.dotCover 179 | 180 | # Visual Studio code coverage results 181 | *.coverage 182 | *.coveragexml 183 | 184 | # NCrunch 185 | _NCrunch_* 186 | .*crunch*.local.xml 187 | nCrunchTemp_* 188 | 189 | # MightyMoose 190 | *.mm.* 191 | AutoTest.Net/ 192 | 193 | # Web workbench (sass) 194 | .sass-cache/ 195 | 196 | # Installshield output folder 197 | [Ee]xpress/ 198 | 199 | # DocProject is a documentation generator add-in 200 | DocProject/buildhelp/ 201 | DocProject/Help/*.HxT 202 | DocProject/Help/*.HxC 203 | DocProject/Help/*.hhc 204 | DocProject/Help/*.hhk 205 | DocProject/Help/*.hhp 206 | DocProject/Help/Html2 207 | DocProject/Help/html 208 | 209 | # Click-Once directory 210 | publish/ 211 | 212 | # Publish Web Output 213 | *.[Pp]ublish.xml 214 | *.azurePubxml 215 | # TODO: Comment the next line if you want to checkin your web deploy settings 216 | # but database connection strings (with potential passwords) will be unencrypted 217 | *.pubxml 218 | *.publishproj 219 | 220 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 221 | # checkin your Azure Web App publish settings, but sensitive information contained 222 | # in these scripts will be unencrypted 223 | PublishScripts/ 224 | 225 | # NuGet Packages 226 | *.nupkg 227 | # The packages folder can be ignored because of Package Restore 228 | **/packages/* 229 | # except build/, which is used as an MSBuild target. 230 | !**/packages/build/ 231 | # Uncomment if necessary however generally it will be regenerated when needed 232 | #!**/packages/repositories.config 233 | # NuGet v3's project.json files produces more ignorable files 234 | *.nuget.props 235 | *.nuget.targets 236 | 237 | # Microsoft Azure Build Output 238 | csx/ 239 | *.build.csdef 240 | 241 | # Microsoft Azure Emulator 242 | ecf/ 243 | rcf/ 244 | 245 | # Windows Store app package directories and files 246 | AppPackages/ 247 | BundleArtifacts/ 248 | Package.StoreAssociation.xml 249 | _pkginfo.txt 250 | 251 | # Visual Studio cache files 252 | # files ending in .cache can be ignored 253 | *.[Cc]ache 254 | # but keep track of directories ending in .cache 255 | !*.[Cc]ache/ 256 | 257 | # Others 258 | ClientBin/ 259 | ~$* 260 | *~ 261 | *.dbmdl 262 | *.dbproj.schemaview 263 | *.jfm 264 | *.pfx 265 | *.publishsettings 266 | orleans.codegen.cs 267 | 268 | # Since there are multiple workflows, uncomment next line to ignore bower_components 269 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 270 | #bower_components/ 271 | 272 | # RIA/Silverlight projects 273 | Generated_Code/ 274 | 275 | # Backup & report files from converting an old project file 276 | # to a newer Visual Studio version. Backup files are not needed, 277 | # because we have git ;-) 278 | _UpgradeReport_Files/ 279 | Backup*/ 280 | UpgradeLog*.XML 281 | UpgradeLog*.htm 282 | 283 | # SQL Server files 284 | *.mdf 285 | *.ldf 286 | *.ndf 287 | 288 | # Business Intelligence projects 289 | *.rdl.data 290 | *.bim.layout 291 | *.bim_*.settings 292 | 293 | # Microsoft Fakes 294 | FakesAssemblies/ 295 | 296 | # GhostDoc plugin setting file 297 | *.GhostDoc.xml 298 | 299 | # Node.js Tools for Visual Studio 300 | .ntvs_analysis.dat 301 | node_modules/ 302 | 303 | # Typescript v1 declaration files 304 | typings/ 305 | 306 | # Visual Studio 6 build log 307 | *.plg 308 | 309 | # Visual Studio 6 workspace options file 310 | *.opt 311 | 312 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 313 | *.vbw 314 | 315 | # Visual Studio LightSwitch build output 316 | **/*.HTMLClient/GeneratedArtifacts 317 | **/*.DesktopClient/GeneratedArtifacts 318 | **/*.DesktopClient/ModelManifest.xml 319 | **/*.Server/GeneratedArtifacts 320 | **/*.Server/ModelManifest.xml 321 | _Pvt_Extensions 322 | 323 | # Paket dependency manager 324 | .paket/paket.exe 325 | paket-files/ 326 | 327 | # FAKE - F# Make 328 | .fake/ 329 | 330 | # JetBrains Rider 331 | .idea/ 332 | *.sln.iml 333 | 334 | # CodeRush 335 | .cr/ 336 | 337 | # Python Tools for Visual Studio (PTVS) 338 | __pycache__/ 339 | *.pyc 340 | 341 | # Cake - Uncomment if you are using it 342 | # tools/** 343 | # !tools/packages.config 344 | 345 | # Telerik's JustMock configuration file 346 | *.jmconfig 347 | 348 | # BizTalk build output 349 | *.btp.cs 350 | *.btm.cs 351 | *.odx.cs 352 | *.xsd.cs 353 | 354 | # End of https://www.gitignore.io/api/osx,windows,visualstudio,visualstudiocode -------------------------------------------------------------------------------- /ASync/src/Azure/JS/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to Azure Functions", 6 | "type": "node", 7 | "request": "attach", 8 | "port": 5858 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/ASyncMng/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Generate a v4 UUID (random) 4 | const uuidV4 = require('uuid/v4'); 5 | 6 | 7 | let ASyncMngClassSingletonRef = null; 8 | let ASyncMngClassSingletonFlag = false; 9 | 10 | // per async API create the following entry 11 | // running state: Running; Completed (which mean success); Failed 12 | // run result: object returned from the API run 13 | // TODO: add time to API data struct - created (to help with timeout in the future) 14 | class ASyncMng { 15 | constructor() { 16 | if (ASyncMngClassSingletonFlag & !ASyncMngClassSingletonRef) { 17 | this.ASyncApiCallList = {}; 18 | 19 | this.ASyncApiCallList["1"] = { "runningState": "Running", "runResult": "" }; 20 | this.ASyncApiCallList["2"] = { "runningState": "Completed", "runResult": "some object here... " }; 21 | } 22 | } 23 | 24 | static getAsyncMng() { 25 | if (ASyncMngClassSingletonFlag === false) { 26 | ASyncMngClassSingletonFlag = true; 27 | if (ASyncMngClassSingletonRef === null) { 28 | ASyncMngClassSingletonRef = new ASyncMng(); 29 | } 30 | } 31 | return ASyncMngClassSingletonRef; 32 | } 33 | 34 | // get all API list 35 | // TODO: need to support paging 36 | getApiList() { 37 | return this.ASyncApiCallList; 38 | } 39 | 40 | // get single API call 41 | getApiCall(ApiCallId) { 42 | return this.ASyncApiCallList[ApiCallId]; 43 | } 44 | 45 | // create a new API call entry in the APICallList with default state 46 | newApiCall() { 47 | const ApiCallId = uuidV4(); 48 | this.ASyncApiCallList[ApiCallId] = { "runningState": "Running", "runResult": "" }; 49 | 50 | return ApiCallId; 51 | } 52 | 53 | 54 | // update API status 55 | updateApiCall(ApiCallId, newRunningState, newRunResult) { 56 | if (this.ASyncApiCallList[ApiCallId]) { 57 | this.ASyncApiCallList[ApiCallId].runningState = newRunningState; 58 | this.ASyncApiCallList[ApiCallId].runResult = newRunResult; 59 | 60 | return this.ASyncApiCallList[ApiCallId]; 61 | } 62 | else { 63 | return false; 64 | } 65 | } 66 | 67 | // should not be used other than for demo purposes 68 | ClearApiList() { 69 | this.ASyncApiCallList = {}; 70 | } 71 | 72 | // should not be used other than for demo purposes 73 | SeedApiList() { 74 | this.ASyncApiCallList["1"] = { "RunningState": "Running", "runResult": "" }; 75 | this.ASyncApiCallList["2"] = { "RunningState": "Completed", "runResult": "some object here... " }; 76 | } 77 | 78 | } 79 | 80 | module.exports = { 81 | ASyncMngClass: ASyncMng 82 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiDelete/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req", 9 | "methods": ["delete"], 10 | "route": "Heroes/" 11 | 12 | }, 13 | { 14 | "type": "http", 15 | "direction": "out", 16 | "name": "res" 17 | }, 18 | { 19 | "type": "queue", 20 | "name": "outputQueueItem", 21 | "queueName": "heors-api-async-dowork", 22 | "connection": "AzureWebJobsDashboard", 23 | "direction": "out" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiDelete/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //const heroes = require('../heroes'); 4 | const HeroesClass = require('../heroes').HeroesClass; 5 | const ASyncMngClass = require('../ASyncMng'). ASyncMngClass; 6 | 7 | //Delete 8 | module.exports = function (context, req) { 9 | context.log('JavaScript API DELETE trigger function processed a request.'); 10 | 11 | const body = req.body; 12 | let returnedHeros = null; 13 | 14 | //validate 15 | if (req.body.id) { 16 | 17 | //get ASync context --> AsyncID 18 | const ApiCallId = ASyncMngClass.getAsyncMng().newApiCall(); 19 | 20 | // TODO: get method from request obj 21 | const qMsg = { 22 | "apiId": ApiCallId, 23 | "method": req.method, 24 | "body": req.body 25 | } 26 | //push msg to q for async processing 27 | context.bindings.outputQueueItem = qMsg; 28 | 29 | // return location for 202 pattern 30 | context.res = { 31 | status: 202, 32 | body: { "msg": "delete hero request captured", "uri": ApiCallId }, 33 | headers: { 34 | 'location': ApiCallId 35 | } 36 | }; 37 | 38 | 39 | /* 40 | returnedHeros = HeroesClass.getHeroesClass().removeHero(req.body.id); 41 | if (returnedHeros) { 42 | context.log('deleted hero ', req.body.id); 43 | 44 | context.res = { 45 | status: 200, 46 | body: { "msg": "successfully deleted hero", "id": req.body.id } 47 | }; 48 | }*/ 49 | // else handle failure at data store 50 | } 51 | else { 52 | context.res = { 53 | status: 422, 54 | body: { "error": "To delete a hero, pass id" } 55 | }; 56 | 57 | } 58 | 59 | context.done(); 60 | }; -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiDelete/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "inpit": "42" 3 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiGet/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req", 9 | "methods": ["get"], 10 | "route": "Heroes/{id:regex(^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$)?}" 11 | 12 | }, 13 | { 14 | "type": "http", 15 | "direction": "out", 16 | "name": "res" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiGet/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //const heroes = require('../heroes'); 4 | const HeroesClass = require('../heroes').HeroesClass; 5 | 6 | //GET 7 | module.exports = function (context, req) { 8 | context.log('JavaScript API GET trigger function processed a request.'); 9 | 10 | const id = context.bindingData.id; 11 | let returnedHeros = null; 12 | 13 | if (id === null) { 14 | returnedHeros = HeroesClass.getHeroesClass().getHeroes(); 15 | context.res = { 16 | status: 200, 17 | body: returnedHeros 18 | }; 19 | } 20 | else { 21 | returnedHeros = HeroesClass.getHeroesClass().getHero(id); 22 | if (returnedHeros) { 23 | context.res = { 24 | status: 200, 25 | body: returnedHeros 26 | }; 27 | } 28 | else { 29 | context.res = { 30 | status: 404, 31 | body: {"error" : "cant find hero with id=",id} 32 | }; 33 | } 34 | } 35 | 36 | 37 | 38 | context.done(); 39 | }; -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiGet/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "inpit": "42" 3 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiPost/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req", 9 | "methods": ["post"], 10 | "route": "Heroes/" 11 | 12 | }, 13 | { 14 | "type": "http", 15 | "direction": "out", 16 | "name": "res" 17 | }, 18 | { 19 | "type": "queue", 20 | "name": "outputQueueItem", 21 | "queueName": "heors-api-async-dowork", 22 | "connection": "AzureWebJobsDashboard", 23 | "direction": "out" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiPost/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const HeroesClass = require('../heroes').HeroesClass; 4 | const ASyncMngClass = require('../ASyncMng').ASyncMngClass; 5 | 6 | //POST 7 | //TODO update a reutn URI to correct path 8 | module.exports = function (context, req) { 9 | context.log('Heroes API POST trigger function processed a request.'); 10 | 11 | const body = req.body; 12 | let returnedHeros = null; 13 | 14 | //validate 15 | if (req.body.name && req.body.superPower) { 16 | 17 | //get ASync context --> AsyncID 18 | const ApiCallId = ASyncMngClass.getAsyncMng().newApiCall(); 19 | 20 | const qMsg = { 21 | "apiId": ApiCallId, 22 | "method": req.method, 23 | "body": req.body 24 | } 25 | //push msg to q 26 | context.bindings.outputQueueItem = qMsg; 27 | 28 | context.res = { 29 | status: 202, 30 | body: { "msg": "Create hero request accepted", "uri": ApiCallId }, 31 | headers: { 32 | 'location': ApiCallId 33 | } 34 | }; 35 | 36 | /* 37 | returnedHeros = HeroesClass.getHeroesClass().addHero(req.body.name, req.body.superPower); 38 | 39 | if (returnedHeros) { 40 | context.log('added a new hero ', JSON.stringify(returnedHeros)); 41 | 42 | context.res = { 43 | status: 200, 44 | body: { "msg": "successfully added a new super hero", "hero": returnedHeros, "uri": "/UID" } 45 | }; 46 | }*/ 47 | // else handle failure at data store 48 | } 49 | else { 50 | context.res = { 51 | status: 422, 52 | body: { "error": "To add a new supper hero, pass name and superpower" } 53 | }; 54 | 55 | } 56 | 57 | context.done(); 58 | }; -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiPost/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "inpit": "42" 3 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiStatus/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req", 9 | "methods": ["get"], 10 | "route": "Heroes/Status/{id:regex(^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$)?}" 11 | 12 | }, 13 | { 14 | "type": "http", 15 | "direction": "out", 16 | "name": "res" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiStatus/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | const ASyncMngClass = require('../ASyncMng').ASyncMngClass; 5 | 6 | //GET 7 | module.exports = function (context, req) { 8 | context.log('JavaScript API GET trigger function processed a request.'); 9 | 10 | const id = context.bindingData.id; 11 | let apiCallList = null; 12 | 13 | if (id === null) { 14 | apiCallList = ASyncMngClass.getAsyncMng().getApiList(); 15 | context.res = { 16 | status: 200, 17 | body: apiCallList 18 | }; 19 | } 20 | else { 21 | apiCallList = ASyncMngClass.getAsyncMng().getApiCall(id); 22 | if (apiCallList) { 23 | context.res = { 24 | status: 200, 25 | body: apiCallList 26 | }; 27 | } 28 | else { 29 | context.res = { 30 | status: 404, 31 | body: {"error" : "cant find call with id=",id} 32 | }; 33 | } 34 | } 35 | 36 | 37 | 38 | context.done(); 39 | }; -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiStatus/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "inpit": "42" 3 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiUpdate/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req", 9 | "methods": ["put"], 10 | "route": "Heroes/" 11 | 12 | }, 13 | { 14 | "type": "http", 15 | "direction": "out", 16 | "name": "res" 17 | }, 18 | { 19 | "type": "queue", 20 | "name": "outputQueueItem", 21 | "queueName": "heors-api-async-dowork", 22 | "connection": "AzureWebJobsDashboard", 23 | "direction": "out" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiUpdate/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //const heroes = require('../heroes'); 4 | const HeroesClass = require('../heroes').HeroesClass; 5 | const ASyncMngClass = require('../ASyncMng'). ASyncMngClass; 6 | 7 | //PUT 8 | module.exports = function (context, req) { 9 | context.log('JavaScript API PUT trigger function processed a request.'); 10 | 11 | const body = req.body; 12 | let returnedHeros = null; 13 | 14 | //validate 15 | if (req.body.id && req.body.name && req.body.superPower) { 16 | 17 | //get ASync context --> AsyncID 18 | const ApiCallId = ASyncMngClass.getAsyncMng().newApiCall(); 19 | 20 | const qMsg = { 21 | "apiId": ApiCallId, 22 | "method": req.method, 23 | "body": req.body 24 | } 25 | //push msg to q 26 | context.bindings.outputQueueItem = qMsg; 27 | 28 | context.res = { 29 | status: 202, 30 | body: { "msg": "Update hero request accepted", "uri": ApiCallId }, 31 | headers: { 32 | 'location': ApiCallId 33 | } 34 | 35 | }; 36 | 37 | /* 38 | returnedHeros = HeroesClass.getHeroesClass().updateHero(req.body.id, req.body.name, req.body.superPower); 39 | if (returnedHeros) { 40 | context.log('Updated a new hero ', JSON.stringify(returnedHeros)); 41 | 42 | context.res = { 43 | status: 200, 44 | body: { "msg": "successfully updated hero", "hero": returnedHeros } 45 | }; 46 | }*/ 47 | // else handle failure at data store 48 | } 49 | else { 50 | context.res = { 51 | status: 422, 52 | body: { "error": "To update a new supper hero, pass existing super hero id, new name and superpower" } 53 | }; 54 | 55 | } 56 | 57 | context.done(); 58 | }; -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HeroesApiUpdate/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "inpit": "42" 3 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HerosAsyncDoWork/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "name": "myQueueItem", 6 | "type": "queueTrigger", 7 | "direction": "in", 8 | "queueName": "heors-api-async-dowork", 9 | "connection": "AzureWebJobsDashboard" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HerosAsyncDoWork/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const HeroesClass = require('../heroes').HeroesClass; 4 | const ASyncMngClass = require('../ASyncMng').ASyncMngClass; 5 | 6 | 7 | var myVar; //used for delay callback TODO: change to promise 8 | 9 | //fake timeout to show async nature 10 | function fakeDelayDoWork(myQueueItem, context) { 11 | let returnedHeros = null; 12 | 13 | try { 14 | 15 | if (myQueueItem.method === "POST") { 16 | returnedHeros = HeroesClass.getHeroesClass().addHero(myQueueItem.body.name, myQueueItem.body.superPower); 17 | 18 | if (returnedHeros) { 19 | context.log('added a new hero ', JSON.stringify(returnedHeros)); 20 | 21 | const temp = ASyncMngClass.getAsyncMng().updateApiCall(myQueueItem.apiId, "Completed", { "msg": "successfully added new hero", "id": returnedHeros }); 22 | } 23 | else { 24 | context.log('FAILD to create a hero ', myQueueItem.body); 25 | const temp = ASyncMngClass.getAsyncMng().updateApiCall(myQueueItem.apiId, "Faild", { "msg": "Faild to add new hero", "id": "" }); 26 | //TODO: handle temp error 27 | } 28 | 29 | } 30 | else if (myQueueItem.method === "PUT") { 31 | returnedHeros = HeroesClass.getHeroesClass().updateHero(myQueueItem.body.id, myQueueItem.body.name, myQueueItem.body.superPower); 32 | if (returnedHeros) { 33 | context.log('Updated a new hero ', JSON.stringify(returnedHeros)); 34 | 35 | const temp = ASyncMngClass.getAsyncMng().updateApiCall(myQueueItem.apiId, "Completed", { "msg": "successfully update hero", "id": myQueueItem.body.id }); 36 | } 37 | else { 38 | context.log('FAILD to update hero ', myQueueItem.body.id); 39 | const temp = ASyncMngClass.getAsyncMng().updateApiCall(myQueueItem.apiId, "Faild", { "msg": "Faild to update hero", "id": myQueueItem.body.id }); 40 | //TODO: handle temp error 41 | } 42 | } 43 | else if (myQueueItem.method === "DELETE") { 44 | returnedHeros = HeroesClass.getHeroesClass().removeHero(myQueueItem.body.id); 45 | if (returnedHeros) { 46 | context.log('deleted hero ', myQueueItem.body.id); 47 | 48 | const temp = ASyncMngClass.getAsyncMng().updateApiCall(myQueueItem.apiId, "Completed", { "msg": "successfully deleted hero", "id": myQueueItem.body.id }); 49 | //TODO: handle temp error 50 | } 51 | else { 52 | context.log('FAILD to deleted hero ', myQueueItem.body.id); 53 | const temp = ASyncMngClass.getAsyncMng().updateApiCall(myQueueItem.apiId, "Faild", { "msg": "Faild to deleted hero", "id": myQueueItem.body.id }); 54 | //TODO: handle temp error 55 | 56 | } 57 | } 58 | else { 59 | //handle error no method 60 | context.log('JavaScript Heros Api ASync Do Work error: no valid method ', myQueueItem.method); 61 | } 62 | } 63 | catch (e) { 64 | //TODO: handle error 65 | 66 | } 67 | finally { 68 | // once deply is done, complete the work and close the function 69 | context.done(); 70 | } 71 | 72 | } 73 | 74 | //Heros Api ASync Do Work 75 | // expects should be already validated 76 | module.exports = function (context, myQueueItem) { 77 | context.log('JavaScript Heros Api ASync Do Work received --> Q Item = ', myQueueItem); 78 | 79 | //validate 80 | if (myQueueItem.apiId && myQueueItem.method && myQueueItem.body) { 81 | 82 | myVar = setTimeout(fakeDelayDoWork, 15000, myQueueItem, context); 83 | } 84 | else { 85 | 86 | //handle error queue item missing param 87 | context.log('JavaScript Heros Api ASync Do Work error: not valid queue item ', myQueueItem); 88 | } 89 | 90 | //context.done(); 91 | } 92 | -------------------------------------------------------------------------------- /ASync/src/Azure/JS/HerosAsyncDoWork/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure" 3 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/TriggerFunc/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req" 9 | }, 10 | { 11 | "type": "http", 12 | "direction": "out", 13 | "name": "res" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/TriggerFunc/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const heroes = require('../heroes'); 4 | const HeroesClass = require('../heroes').HeroesClass; 5 | 6 | 7 | module.exports = function (context, req) { 8 | context.log('JavaScript HTTP trigger function processed a request.'); 9 | 10 | if (req.query.input || (req.input && req.body.input)) { 11 | 12 | const msg = { 13 | "input": req.query.input 14 | }; 15 | 16 | // write to Azure Q to be picked up by next function 17 | //context.bindings.outputQueueItem = msg; 18 | 19 | //const heroesList = heroes.getHeroes(); 20 | //context.log('Heroes = ', heroesList); 21 | 22 | let hc = new HeroesClass(); 23 | hc = HeroesClass.getHeroesClass(); 24 | let hc1 = HeroesClass.getHeroesClass(); 25 | context.log('Heroes = ', hc.getHeroes()); 26 | 27 | let newHero = hc.addHero("Darth Vader", "Most powerful force wielder"); 28 | context.log('Heroes = ', hc.getHeroes()); 29 | 30 | let tempUuid = "aaa"; 31 | newHero = hc.getHero(tempUuid); 32 | 33 | hc.updateHero(tempUuid,"new name goes here", "new superpower goes here"); 34 | context.log('Heroes = ', hc.getHeroes()); 35 | 36 | hc.removeHero(tempUuid); 37 | context.log('Heroes = ', hc.getHeroes()); 38 | 39 | context.res = { 40 | // status: 200, /* Defaults to 200 */ 41 | body: "My super heros " + JSON.stringify(hc.getHeroes()) 42 | }; 43 | } 44 | else { 45 | context.res = { 46 | status: 400, 47 | body: "Please pass input on the query string" 48 | }; 49 | } 50 | context.done(); 51 | }; -------------------------------------------------------------------------------- /ASync/src/Azure/JS/TriggerFunc/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "inpit": "42" 3 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/heroes/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Generate a v4 UUID (random) 4 | const uuidV4 = require('uuid/v4'); 5 | 6 | 7 | let HerosClassSingletonRef = null; 8 | let HerosClassSingletonFlag = false; 9 | 10 | class Heroes { 11 | constructor() { 12 | if (HerosClassSingletonFlag & !HerosClassSingletonRef) { 13 | this.heroesList = {}; 14 | 15 | this.heroesList["36c9ee83-0128-42e7-833e-d37f89c8c74e"] = { "name": "Dr. Evil", "superPower": "super smart" }; 16 | this.heroesList["1ae0d528-4dfe-4b31-a8d2-4d223780c882"] = { "name": "Magneto", "superPower": "magnetism" }; 17 | this.heroesList["60bf2be7-552f-447d-a23d-916da876e28c"] = { "name": "Lex Luthor", "superPower": "Knows where to find kryptonite" }; 18 | this.heroesList["84221d4d-9caa-410a-b32c-d755774c6d64"] = { "name": "Loki", "superPower": "Looks like other people" }; 19 | this.heroesList["490a1c14-9a96-40a8-9888-aa26a860dfd2"] = { "name": "Bane", "superPower": "Broke the Bat" }; 20 | } 21 | } 22 | 23 | static getHeroesClass() { 24 | if (HerosClassSingletonFlag === false) { 25 | HerosClassSingletonFlag = true; 26 | if (HerosClassSingletonRef === null) { 27 | HerosClassSingletonRef = new Heroes(); 28 | } 29 | } 30 | return HerosClassSingletonRef; 31 | } 32 | 33 | getHeroes() { 34 | return this.heroesList; 35 | } 36 | 37 | getHero(heroUuid) { 38 | return this.heroesList[heroUuid]; 39 | } 40 | 41 | // TODO: validate input, handle errors, etc... 42 | addHero(name, superPower) { 43 | const tempUuid = uuidV4(); 44 | this.heroesList[tempUuid] = { "name": name, "superPower": superPower }; 45 | 46 | return tempUuid;//this.heroesList[tempUuid]; 47 | } 48 | 49 | 50 | removeHero(heroUuid) { 51 | if (this.heroesList[heroUuid]) { 52 | delete this.heroesList[heroUuid]; 53 | return true; 54 | } 55 | else return false; 56 | } 57 | 58 | 59 | updateHero(heroUuid, name, superPower) { 60 | if (this.heroesList[heroUuid]) { 61 | this.heroesList[heroUuid].name = name; 62 | this.heroesList[heroUuid].superPower = superPower; 63 | 64 | return this.heroesList[heroUuid]; 65 | } 66 | else { 67 | return false; 68 | } 69 | } 70 | 71 | } 72 | 73 | module.exports = { 74 | HeroesClass: Heroes 75 | } -------------------------------------------------------------------------------- /ASync/src/Azure/JS/host.json: -------------------------------------------------------------------------------- 1 | {"id":"491ac3e8ec2e448bbd948242f45d0231"} -------------------------------------------------------------------------------- /ASync/src/Azure/JS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asyncfunc", 3 | "version": "1.0.0", 4 | "description": "ASync HTTP Response (202) Pattern", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Yochay Kiriaty", 10 | "license": "ISC", 11 | "dependencies": { 12 | "uuid": "^3.0.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Docs/Images/functionChain_1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yochay/serverlesspatterns/352052fdc76348c4285cd3094ca113a021e82236/Docs/Images/functionChain_1.JPG -------------------------------------------------------------------------------- /FunctionsChaining/readme.md: -------------------------------------------------------------------------------- 1 | # Function Chaining 2 | 3 | In a nutshell, Functions Chaining is ‘connecting’ a series of Functions together to do a certain task. Since you can’t easily ‘connect’ Functions today (ignore Azure Logic Apps or AWS Step Functions for a second), you need to send the output of one function to be the input of the next function, thus creating a chain. It looks something like the following illustration (thank you @cgillum for the graphics). 4 | 5 | Simple Functions Chain: 6 | ![alt text](../Docs/images/functionChain_1.jpg "Functions Chaining with queues") 7 | 8 | You might notice the queues in between Functions, which are used as a “communication channel” between the different Functions. Since you can’t call one function from another, it is up to you to setup queues (or use AWS SNS) to facilitate the Function chain. -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,windows,visualstudio,visualstudiocode 3 | 4 | ### OSX ### 5 | *.DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | 13 | # Thumbnails 14 | ._* 15 | 16 | # Files that might appear in the root of a volume 17 | .DocumentRevisions-V100 18 | .fseventsd 19 | .Spotlight-V100 20 | .TemporaryItems 21 | .Trashes 22 | .VolumeIcon.icns 23 | .com.apple.timemachine.donotpresent 24 | 25 | # Directories potentially created on remote AFP share 26 | .AppleDB 27 | .AppleDesktop 28 | Network Trash Folder 29 | Temporary Items 30 | .apdisk 31 | 32 | ### VisualStudioCode ### 33 | .vscode/* 34 | !.vscode/settings.json 35 | !.vscode/tasks.json 36 | !.vscode/launch.json 37 | !.vscode/extensions.json 38 | 39 | ### Windows ### 40 | # Windows thumbnail cache files 41 | Thumbs.db 42 | ehthumbs.db 43 | ehthumbs_vista.db 44 | 45 | # Folder config file 46 | Desktop.ini 47 | 48 | # Recycle Bin used on file shares 49 | $RECYCLE.BIN/ 50 | 51 | # Windows Installer files 52 | *.cab 53 | *.msi 54 | *.msm 55 | *.msp 56 | 57 | # Windows shortcuts 58 | *.lnk 59 | 60 | ### VisualStudio ### 61 | ## Ignore Visual Studio temporary files, build results, and 62 | ## files generated by popular Visual Studio add-ons. 63 | ## 64 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 65 | 66 | # User-specific files 67 | *.suo 68 | *.user 69 | *.userosscache 70 | *.sln.docstates 71 | 72 | # User-specific files (MonoDevelop/Xamarin Studio) 73 | *.userprefs 74 | 75 | # Build results 76 | [Dd]ebug/ 77 | [Dd]ebugPublic/ 78 | [Rr]elease/ 79 | [Rr]eleases/ 80 | x64/ 81 | x86/ 82 | bld/ 83 | [Bb]in/ 84 | [Oo]bj/ 85 | [Ll]og/ 86 | 87 | # Visual Studio 2015 cache/options directory 88 | .vs/ 89 | # Uncomment if you have tasks that create the project's static files in wwwroot 90 | #wwwroot/ 91 | 92 | # Azure Functions 93 | project.lock.json 94 | appsetting.json 95 | 96 | # MSTest test Results 97 | [Tt]est[Rr]esult*/ 98 | [Bb]uild[Ll]og.* 99 | 100 | # NUNIT 101 | *.VisualState.xml 102 | TestResult.xml 103 | 104 | # Build Results of an ATL Project 105 | [Dd]ebugPS/ 106 | [Rr]eleasePS/ 107 | dlldata.c 108 | 109 | # .NET Core 110 | project.lock.json 111 | project.fragment.lock.json 112 | artifacts/ 113 | **/Properties/launchSettings.json 114 | 115 | *_i.c 116 | *_p.c 117 | *_i.h 118 | *.ilk 119 | *.meta 120 | *.obj 121 | *.pch 122 | *.pdb 123 | *.pgc 124 | *.pgd 125 | *.rsp 126 | *.sbr 127 | *.tlb 128 | *.tli 129 | *.tlh 130 | *.tmp 131 | *.tmp_proj 132 | *.log 133 | *.vspscc 134 | *.vssscc 135 | .builds 136 | *.pidb 137 | *.svclog 138 | *.scc 139 | 140 | # Chutzpah Test files 141 | _Chutzpah* 142 | 143 | # Visual C++ cache files 144 | ipch/ 145 | *.aps 146 | *.ncb 147 | *.opendb 148 | *.opensdf 149 | *.sdf 150 | *.cachefile 151 | *.VC.db 152 | *.VC.VC.opendb 153 | 154 | # Visual Studio profiler 155 | *.psess 156 | *.vsp 157 | *.vspx 158 | *.sap 159 | 160 | # TFS 2012 Local Workspace 161 | $tf/ 162 | 163 | # Guidance Automation Toolkit 164 | *.gpState 165 | 166 | # ReSharper is a .NET coding add-in 167 | _ReSharper*/ 168 | *.[Rr]e[Ss]harper 169 | *.DotSettings.user 170 | 171 | # JustCode is a .NET coding add-in 172 | .JustCode 173 | 174 | # TeamCity is a build add-in 175 | _TeamCity* 176 | 177 | # DotCover is a Code Coverage Tool 178 | *.dotCover 179 | 180 | # Visual Studio code coverage results 181 | *.coverage 182 | *.coveragexml 183 | 184 | # NCrunch 185 | _NCrunch_* 186 | .*crunch*.local.xml 187 | nCrunchTemp_* 188 | 189 | # MightyMoose 190 | *.mm.* 191 | AutoTest.Net/ 192 | 193 | # Web workbench (sass) 194 | .sass-cache/ 195 | 196 | # Installshield output folder 197 | [Ee]xpress/ 198 | 199 | # DocProject is a documentation generator add-in 200 | DocProject/buildhelp/ 201 | DocProject/Help/*.HxT 202 | DocProject/Help/*.HxC 203 | DocProject/Help/*.hhc 204 | DocProject/Help/*.hhk 205 | DocProject/Help/*.hhp 206 | DocProject/Help/Html2 207 | DocProject/Help/html 208 | 209 | # Click-Once directory 210 | publish/ 211 | 212 | # Publish Web Output 213 | *.[Pp]ublish.xml 214 | *.azurePubxml 215 | # TODO: Comment the next line if you want to checkin your web deploy settings 216 | # but database connection strings (with potential passwords) will be unencrypted 217 | *.pubxml 218 | *.publishproj 219 | 220 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 221 | # checkin your Azure Web App publish settings, but sensitive information contained 222 | # in these scripts will be unencrypted 223 | PublishScripts/ 224 | 225 | # NuGet Packages 226 | *.nupkg 227 | # The packages folder can be ignored because of Package Restore 228 | **/packages/* 229 | # except build/, which is used as an MSBuild target. 230 | !**/packages/build/ 231 | # Uncomment if necessary however generally it will be regenerated when needed 232 | #!**/packages/repositories.config 233 | # NuGet v3's project.json files produces more ignorable files 234 | *.nuget.props 235 | *.nuget.targets 236 | 237 | # Microsoft Azure Build Output 238 | csx/ 239 | *.build.csdef 240 | 241 | # Microsoft Azure Emulator 242 | ecf/ 243 | rcf/ 244 | 245 | # Windows Store app package directories and files 246 | AppPackages/ 247 | BundleArtifacts/ 248 | Package.StoreAssociation.xml 249 | _pkginfo.txt 250 | 251 | # Visual Studio cache files 252 | # files ending in .cache can be ignored 253 | *.[Cc]ache 254 | # but keep track of directories ending in .cache 255 | !*.[Cc]ache/ 256 | 257 | # Others 258 | ClientBin/ 259 | ~$* 260 | *~ 261 | *.dbmdl 262 | *.dbproj.schemaview 263 | *.jfm 264 | *.pfx 265 | *.publishsettings 266 | orleans.codegen.cs 267 | 268 | # Since there are multiple workflows, uncomment next line to ignore bower_components 269 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 270 | #bower_components/ 271 | 272 | # RIA/Silverlight projects 273 | Generated_Code/ 274 | 275 | # Backup & report files from converting an old project file 276 | # to a newer Visual Studio version. Backup files are not needed, 277 | # because we have git ;-) 278 | _UpgradeReport_Files/ 279 | Backup*/ 280 | UpgradeLog*.XML 281 | UpgradeLog*.htm 282 | 283 | # SQL Server files 284 | *.mdf 285 | *.ldf 286 | *.ndf 287 | 288 | # Business Intelligence projects 289 | *.rdl.data 290 | *.bim.layout 291 | *.bim_*.settings 292 | 293 | # Microsoft Fakes 294 | FakesAssemblies/ 295 | 296 | # GhostDoc plugin setting file 297 | *.GhostDoc.xml 298 | 299 | # Node.js Tools for Visual Studio 300 | .ntvs_analysis.dat 301 | node_modules/ 302 | 303 | # Typescript v1 declaration files 304 | typings/ 305 | 306 | # Visual Studio 6 build log 307 | *.plg 308 | 309 | # Visual Studio 6 workspace options file 310 | *.opt 311 | 312 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 313 | *.vbw 314 | 315 | # Visual Studio LightSwitch build output 316 | **/*.HTMLClient/GeneratedArtifacts 317 | **/*.DesktopClient/GeneratedArtifacts 318 | **/*.DesktopClient/ModelManifest.xml 319 | **/*.Server/GeneratedArtifacts 320 | **/*.Server/ModelManifest.xml 321 | _Pvt_Extensions 322 | 323 | # Paket dependency manager 324 | .paket/paket.exe 325 | paket-files/ 326 | 327 | # FAKE - F# Make 328 | .fake/ 329 | 330 | # JetBrains Rider 331 | .idea/ 332 | *.sln.iml 333 | 334 | # CodeRush 335 | .cr/ 336 | 337 | # Python Tools for Visual Studio (PTVS) 338 | __pycache__/ 339 | *.pyc 340 | 341 | # Cake - Uncomment if you are using it 342 | # tools/** 343 | # !tools/packages.config 344 | 345 | # Telerik's JustMock configuration file 346 | *.jmconfig 347 | 348 | # BizTalk build output 349 | *.btp.cs 350 | *.btm.cs 351 | *.odx.cs 352 | *.xsd.cs 353 | 354 | # End of https://www.gitignore.io/api/osx,windows,visualstudio,visualstudiocode -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to Azure Functions", 6 | "type": "node", 7 | "request": "attach", 8 | "port": 5858 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func1/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "name": "myQueueItem", 6 | "type": "queueTrigger", 7 | "direction": "in", 8 | "queueName": "funcchainoutqueue1", 9 | "connection": "AzureWebJobsDashboard" 10 | }, 11 | { 12 | "type": "queue", 13 | "name": "outputQueueItem", 14 | "queueName": "funcchainoutqueue2", 15 | "connection": "AzureWebJobsDashboard", 16 | "direction": "out" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func1/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // 4 | function doWork(msg) { 5 | 6 | msg["func1"] = "new string from Function 1"; 7 | 8 | return msg; 9 | } 10 | 11 | module.exports = function (context, myQueueItem) { 12 | context.log('JavaScript Func 1 received --> Q Item = ', myQueueItem); 13 | 14 | if (myQueueItem) { 15 | 16 | const workDone = doWork(myQueueItem); 17 | 18 | // write to Azure Q to be picked up by next function 19 | context.bindings.outputQueueItem = workDone; 20 | } 21 | else{ 22 | // log error 23 | // handle error 24 | } 25 | 26 | context.done(); 27 | }; -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func1/readme.md: -------------------------------------------------------------------------------- 1 | # QueueTrigger - JavaScript 2 | 3 | The `QueueTrigger` makes it incredibly easy to react to new Queues inside of Azure Queue Storage. This sample demonstrates a simple use case of processing data from a given Queue using C#. 4 | 5 | ## How it works 6 | 7 | For a `QueueTrigger` to work, you provide a path which dictates where the queue messages are located inside your container. 8 | 9 | ## Learn more 10 | 11 | Documentation -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func1/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "inpit": "42" 3 | } -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func2/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "name": "myQueueItem", 6 | "type": "queueTrigger", 7 | "direction": "in", 8 | "queueName": "funcchainoutqueue2", 9 | "connection": "AzureWebJobsDashboard" 10 | }, 11 | { 12 | "type": "queue", 13 | "name": "outputQueueItem", 14 | "queueName": "funcchainoutqueue3", 15 | "connection": "AzureWebJobsDashboard", 16 | "direction": "out" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func2/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // 4 | function doWork(msg) { 5 | 6 | msg["func2"] = "new string from Function 2"; 7 | 8 | return msg; 9 | } 10 | 11 | 12 | module.exports = function (context, myQueueItem) { 13 | context.log('JavaScript Func 2 received --> Q Item = ', myQueueItem); 14 | 15 | if (myQueueItem) { 16 | 17 | const workDone = doWork(myQueueItem); 18 | 19 | // write to Azure Q to be picked up by next function 20 | context.bindings.outputQueueItem = workDone; 21 | } 22 | else{ 23 | // log error 24 | // handle error 25 | } 26 | 27 | context.done(); 28 | }; -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func2/readme.md: -------------------------------------------------------------------------------- 1 | # QueueTrigger - JavaScript 2 | 3 | The `QueueTrigger` makes it incredibly easy to react to new Queues inside of Azure Queue Storage. This sample demonstrates a simple use case of processing data from a given Queue using C#. 4 | 5 | ## How it works 6 | 7 | For a `QueueTrigger` to work, you provide a path which dictates where the queue messages are located inside your container. 8 | 9 | ## Learn more 10 | 11 | Documentation -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func2/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "inpit": "42" 3 | } -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func3/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "name": "myQueueItem", 6 | "type": "queueTrigger", 7 | "direction": "in", 8 | "queueName": "funcchainoutqueue3", 9 | "connection": "AzureWebJobsDashboard" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func3/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // 4 | function doWork(msg) { 5 | 6 | msg["func3"] = "new string from Function 3"; 7 | 8 | return msg; 9 | } 10 | 11 | 12 | module.exports = function (context, myQueueItem) { 13 | context.log('JavaScript Func 3 received --> Q Item = ', myQueueItem); 14 | 15 | if (myQueueItem) { 16 | 17 | const workDone = doWork(myQueueItem); 18 | 19 | // nothing else to to. Maybe update some datastore about compliting this task 20 | 21 | context.log('JavaScript Func 3 completed ', workDone); 22 | } 23 | else { 24 | // log error 25 | // handle error 26 | } 27 | context.done(); 28 | }; -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func3/readme.md: -------------------------------------------------------------------------------- 1 | # QueueTrigger - JavaScript 2 | 3 | The `QueueTrigger` makes it incredibly easy to react to new Queues inside of Azure Queue Storage. This sample demonstrates a simple use case of processing data from a given Queue using C#. 4 | 5 | ## How it works 6 | 7 | For a `QueueTrigger` to work, you provide a path which dictates where the queue messages are located inside your container. 8 | 9 | ## Learn more 10 | 11 | Documentation -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/Func3/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "inpit": "42" 3 | } -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/TriggerFunc/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req" 9 | }, 10 | { 11 | "type": "http", 12 | "direction": "out", 13 | "name": "res" 14 | }, 15 | { 16 | "type": "queue", 17 | "name": "outputQueueItem", 18 | "queueName": "funcchainoutqueue1", 19 | "connection": "AzureWebJobsDashboard", 20 | "direction": "out" 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/TriggerFunc/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (context, req) { 4 | context.log('JavaScript HTTP trigger function processed a request.'); 5 | 6 | if (req.query.input || (req.input && req.body.input)) { 7 | 8 | const msg = { 9 | "input": req.query.input || "" 10 | }; 11 | 12 | // write to Azure Q to be picked up by next function 13 | context.bindings.outputQueueItem = msg; 14 | //outputQueueItem = msg; 15 | 16 | context.res = { 17 | // status: 200, /* Defaults to 200 */ 18 | body: "received " +msg.input + " sending down the pipe --> " + JSON.stringify(msg) 19 | }; 20 | } 21 | else { 22 | context.res = { 23 | status: 400, 24 | body: "Please pass input on the query string" 25 | }; 26 | } 27 | context.done(); 28 | }; -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/TriggerFunc/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "input": "42" 3 | } -------------------------------------------------------------------------------- /FunctionsChaining/src/Azure/JS/host.json: -------------------------------------------------------------------------------- 1 | {"id":"491ac3e8ec2e448bbd948242f45d023b"} -------------------------------------------------------------------------------- /FunctionsChainingTransaction/readme.md: -------------------------------------------------------------------------------- 1 | TODO 2 | - use correlationId to emit AI traces 3 | -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,windows,visualstudio,visualstudiocode 3 | 4 | ### OSX ### 5 | *.DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | 13 | # Thumbnails 14 | ._* 15 | 16 | # Files that might appear in the root of a volume 17 | .DocumentRevisions-V100 18 | .fseventsd 19 | .Spotlight-V100 20 | .TemporaryItems 21 | .Trashes 22 | .VolumeIcon.icns 23 | .com.apple.timemachine.donotpresent 24 | 25 | # Directories potentially created on remote AFP share 26 | .AppleDB 27 | .AppleDesktop 28 | Network Trash Folder 29 | Temporary Items 30 | .apdisk 31 | 32 | ### VisualStudioCode ### 33 | .vscode/* 34 | !.vscode/settings.json 35 | !.vscode/tasks.json 36 | !.vscode/launch.json 37 | !.vscode/extensions.json 38 | 39 | ### Windows ### 40 | # Windows thumbnail cache files 41 | Thumbs.db 42 | ehthumbs.db 43 | ehthumbs_vista.db 44 | 45 | # Folder config file 46 | Desktop.ini 47 | 48 | # Recycle Bin used on file shares 49 | $RECYCLE.BIN/ 50 | 51 | # Windows Installer files 52 | *.cab 53 | *.msi 54 | *.msm 55 | *.msp 56 | 57 | # Windows shortcuts 58 | *.lnk 59 | 60 | ### VisualStudio ### 61 | ## Ignore Visual Studio temporary files, build results, and 62 | ## files generated by popular Visual Studio add-ons. 63 | ## 64 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 65 | 66 | # User-specific files 67 | *.suo 68 | *.user 69 | *.userosscache 70 | *.sln.docstates 71 | 72 | # User-specific files (MonoDevelop/Xamarin Studio) 73 | *.userprefs 74 | 75 | # Build results 76 | [Dd]ebug/ 77 | [Dd]ebugPublic/ 78 | [Rr]elease/ 79 | [Rr]eleases/ 80 | x64/ 81 | x86/ 82 | bld/ 83 | [Bb]in/ 84 | [Oo]bj/ 85 | [Ll]og/ 86 | 87 | # Visual Studio 2015 cache/options directory 88 | .vs/ 89 | # Uncomment if you have tasks that create the project's static files in wwwroot 90 | #wwwroot/ 91 | 92 | # Azure Functions 93 | project.lock.json 94 | appsetting.json 95 | 96 | # MSTest test Results 97 | [Tt]est[Rr]esult*/ 98 | [Bb]uild[Ll]og.* 99 | 100 | # NUNIT 101 | *.VisualState.xml 102 | TestResult.xml 103 | 104 | # Build Results of an ATL Project 105 | [Dd]ebugPS/ 106 | [Rr]eleasePS/ 107 | dlldata.c 108 | 109 | # .NET Core 110 | project.lock.json 111 | project.fragment.lock.json 112 | artifacts/ 113 | **/Properties/launchSettings.json 114 | 115 | *_i.c 116 | *_p.c 117 | *_i.h 118 | *.ilk 119 | *.meta 120 | *.obj 121 | *.pch 122 | *.pdb 123 | *.pgc 124 | *.pgd 125 | *.rsp 126 | *.sbr 127 | *.tlb 128 | *.tli 129 | *.tlh 130 | *.tmp 131 | *.tmp_proj 132 | *.log 133 | *.vspscc 134 | *.vssscc 135 | .builds 136 | *.pidb 137 | *.svclog 138 | *.scc 139 | 140 | # Chutzpah Test files 141 | _Chutzpah* 142 | 143 | # Visual C++ cache files 144 | ipch/ 145 | *.aps 146 | *.ncb 147 | *.opendb 148 | *.opensdf 149 | *.sdf 150 | *.cachefile 151 | *.VC.db 152 | *.VC.VC.opendb 153 | 154 | # Visual Studio profiler 155 | *.psess 156 | *.vsp 157 | *.vspx 158 | *.sap 159 | 160 | # TFS 2012 Local Workspace 161 | $tf/ 162 | 163 | # Guidance Automation Toolkit 164 | *.gpState 165 | 166 | # ReSharper is a .NET coding add-in 167 | _ReSharper*/ 168 | *.[Rr]e[Ss]harper 169 | *.DotSettings.user 170 | 171 | # JustCode is a .NET coding add-in 172 | .JustCode 173 | 174 | # TeamCity is a build add-in 175 | _TeamCity* 176 | 177 | # DotCover is a Code Coverage Tool 178 | *.dotCover 179 | 180 | # Visual Studio code coverage results 181 | *.coverage 182 | *.coveragexml 183 | 184 | # NCrunch 185 | _NCrunch_* 186 | .*crunch*.local.xml 187 | nCrunchTemp_* 188 | 189 | # MightyMoose 190 | *.mm.* 191 | AutoTest.Net/ 192 | 193 | # Web workbench (sass) 194 | .sass-cache/ 195 | 196 | # Installshield output folder 197 | [Ee]xpress/ 198 | 199 | # DocProject is a documentation generator add-in 200 | DocProject/buildhelp/ 201 | DocProject/Help/*.HxT 202 | DocProject/Help/*.HxC 203 | DocProject/Help/*.hhc 204 | DocProject/Help/*.hhk 205 | DocProject/Help/*.hhp 206 | DocProject/Help/Html2 207 | DocProject/Help/html 208 | 209 | # Click-Once directory 210 | publish/ 211 | 212 | # Publish Web Output 213 | *.[Pp]ublish.xml 214 | *.azurePubxml 215 | # TODO: Comment the next line if you want to checkin your web deploy settings 216 | # but database connection strings (with potential passwords) will be unencrypted 217 | *.pubxml 218 | *.publishproj 219 | 220 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 221 | # checkin your Azure Web App publish settings, but sensitive information contained 222 | # in these scripts will be unencrypted 223 | PublishScripts/ 224 | 225 | # NuGet Packages 226 | *.nupkg 227 | # The packages folder can be ignored because of Package Restore 228 | **/packages/* 229 | # except build/, which is used as an MSBuild target. 230 | !**/packages/build/ 231 | # Uncomment if necessary however generally it will be regenerated when needed 232 | #!**/packages/repositories.config 233 | # NuGet v3's project.json files produces more ignorable files 234 | *.nuget.props 235 | *.nuget.targets 236 | 237 | # Microsoft Azure Build Output 238 | csx/ 239 | *.build.csdef 240 | 241 | # Microsoft Azure Emulator 242 | ecf/ 243 | rcf/ 244 | 245 | # Windows Store app package directories and files 246 | AppPackages/ 247 | BundleArtifacts/ 248 | Package.StoreAssociation.xml 249 | _pkginfo.txt 250 | 251 | # Visual Studio cache files 252 | # files ending in .cache can be ignored 253 | *.[Cc]ache 254 | # but keep track of directories ending in .cache 255 | !*.[Cc]ache/ 256 | 257 | # Others 258 | ClientBin/ 259 | ~$* 260 | *~ 261 | *.dbmdl 262 | *.dbproj.schemaview 263 | *.jfm 264 | *.pfx 265 | *.publishsettings 266 | orleans.codegen.cs 267 | 268 | # Since there are multiple workflows, uncomment next line to ignore bower_components 269 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 270 | #bower_components/ 271 | 272 | # RIA/Silverlight projects 273 | Generated_Code/ 274 | 275 | # Backup & report files from converting an old project file 276 | # to a newer Visual Studio version. Backup files are not needed, 277 | # because we have git ;-) 278 | _UpgradeReport_Files/ 279 | Backup*/ 280 | UpgradeLog*.XML 281 | UpgradeLog*.htm 282 | 283 | # SQL Server files 284 | *.mdf 285 | *.ldf 286 | *.ndf 287 | 288 | # Business Intelligence projects 289 | *.rdl.data 290 | *.bim.layout 291 | *.bim_*.settings 292 | 293 | # Microsoft Fakes 294 | FakesAssemblies/ 295 | 296 | # GhostDoc plugin setting file 297 | *.GhostDoc.xml 298 | 299 | # Node.js Tools for Visual Studio 300 | .ntvs_analysis.dat 301 | node_modules/ 302 | 303 | # Typescript v1 declaration files 304 | typings/ 305 | 306 | # Visual Studio 6 build log 307 | *.plg 308 | 309 | # Visual Studio 6 workspace options file 310 | *.opt 311 | 312 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 313 | *.vbw 314 | 315 | # Visual Studio LightSwitch build output 316 | **/*.HTMLClient/GeneratedArtifacts 317 | **/*.DesktopClient/GeneratedArtifacts 318 | **/*.DesktopClient/ModelManifest.xml 319 | **/*.Server/GeneratedArtifacts 320 | **/*.Server/ModelManifest.xml 321 | _Pvt_Extensions 322 | 323 | # Paket dependency manager 324 | .paket/paket.exe 325 | paket-files/ 326 | 327 | # FAKE - F# Make 328 | .fake/ 329 | 330 | # JetBrains Rider 331 | .idea/ 332 | *.sln.iml 333 | 334 | # CodeRush 335 | .cr/ 336 | 337 | # Python Tools for Visual Studio (PTVS) 338 | __pycache__/ 339 | *.pyc 340 | 341 | # Cake - Uncomment if you are using it 342 | # tools/** 343 | # !tools/packages.config 344 | 345 | # Telerik's JustMock configuration file 346 | *.jmconfig 347 | 348 | # BizTalk build output 349 | *.btp.cs 350 | *.btm.cs 351 | *.odx.cs 352 | *.xsd.cs 353 | 354 | # End of https://www.gitignore.io/api/osx,windows,visualstudio,visualstudiocode -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to Azure Functions", 6 | "type": "node", 7 | "request": "attach", 8 | "port": 5858 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/ChainQMsg/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | // Generate a v4 UUID (random) 5 | const uuidV4 = require('uuid/v4'); 6 | 7 | 8 | let singleton = null; 9 | 10 | class ChainQMsg { 11 | constructor() { 12 | this.objs = {} 13 | } 14 | 15 | static newChainQMsg(triggerInputValue, triggerInputErrorRatio) { 16 | return { 17 | "history": [], 18 | "funcRes": { 19 | "input": triggerInputValue || 42, 20 | "errorratio": triggerInputErrorRatio || 100 21 | }, 22 | "undo": false, 23 | "correlationId" : uuidV4() 24 | }; 25 | } 26 | 27 | static updateChainQMsg(msg, doneWork, funcName) { 28 | if (!msg) { 29 | //TODO handle error! 30 | } 31 | //else 32 | 33 | msg.history.push( 34 | { 35 | "from": funcName, 36 | "input": { 37 | "input": msg.funcRes.input, 38 | "errorratio": msg.funcRes.errorratio 39 | } 40 | } 41 | ); 42 | 43 | msg.funcRes.input = doneWork; 44 | 45 | return msg; 46 | } 47 | 48 | 49 | static getChainQMsg() { 50 | if (singleton === null) { 51 | singleton = new ChainQMsg(); 52 | } 53 | return singleton; 54 | } 55 | } 56 | 57 | 58 | module.exports = { 59 | ChainQMsg 60 | } -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func1/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "name": "myQueueItem", 6 | "type": "queueTrigger", 7 | "direction": "in", 8 | "queueName": "outqueue1", 9 | "connection": "AzureWebJobsDashboard" 10 | }, 11 | { 12 | "type": "queue", 13 | "name": "outputQueueItem", 14 | "queueName": "outqueue2", 15 | "connection": "AzureWebJobsDashboard", 16 | "direction": "out" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func1/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ChainQMsg = require('../ChainQMsg').ChainQMsg; 4 | 5 | // 6 | function doWork(funcRes) { 7 | const res = funcRes.input * 2; 8 | 9 | return res; 10 | } 11 | 12 | // 13 | function undoWork(funcRes) { 14 | const res = funcRes.input / 2; 15 | 16 | return res; 17 | } 18 | 19 | module.exports = function (context, myQueueItem) { 20 | context.log('JavaScript Func 1 received --> Q Item = ', myQueueItem); 21 | 22 | if (myQueueItem && myQueueItem.undo === false) { 23 | 24 | const work = doWork(myQueueItem.funcRes); 25 | const updatedMsg = ChainQMsg.updateChainQMsg(myQueueItem, work, "Func1"); 26 | 27 | // write to Azure Q to be picked up by next function 28 | context.bindings.outputQueueItem = updatedMsg; 29 | } 30 | else if (myQueueItem && myQueueItem.undo === true) { 31 | const lastFunc = myQueueItem.history[myQueueItem.history.length - 1]; 32 | 33 | if (lastFunc.from === "Func1") { 34 | const undoRes = undoWork(myQueueItem.funcRes); 35 | if (undoRes === lastFunc.input.input) { 36 | context.log('Func1 undo successful! undoRes = ' +undoRes); 37 | } 38 | 39 | //clear history 40 | myQueueItem.history.pop(); 41 | } 42 | } 43 | 44 | context.done(); 45 | }; -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func1/readme.md: -------------------------------------------------------------------------------- 1 | # QueueTrigger - JavaScript 2 | 3 | The `QueueTrigger` makes it incredibly easy to react to new Queues inside of Azure Queue Storage. This sample demonstrates a simple use case of processing data from a given Queue using C#. 4 | 5 | ## How it works 6 | 7 | For a `QueueTrigger` to work, you provide a path which dictates where the queue messages are located inside your container. 8 | 9 | ## Learn more 10 | 11 | Documentation -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func1/sample.dat: -------------------------------------------------------------------------------- 1 | sample queue data -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func2/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "name": "myQueueItem", 6 | "type": "queueTrigger", 7 | "direction": "in", 8 | "queueName": "outqueue2", 9 | "connection": "AzureWebJobsDashboard" 10 | }, 11 | { 12 | "type": "queue", 13 | "name": "outputQueueItem", 14 | "queueName": "outqueue3", 15 | "connection": "AzureWebJobsDashboard", 16 | "direction": "out" 17 | }, 18 | { 19 | "type": "queue", 20 | "name": "errorQueueItem", 21 | "queueName": "outqueue1", 22 | "connection": "AzureWebJobsDashboard", 23 | "direction": "out" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func2/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ChainQMsg = require('../ChainQMsg').ChainQMsg; 4 | 5 | // 6 | function doWork(funcRes) { 7 | const res = funcRes.input * 2; 8 | 9 | return res; 10 | } 11 | 12 | // 13 | function undoWork(funcRes) { 14 | const res = funcRes.input / 2; 15 | 16 | return res; 17 | } 18 | 19 | module.exports = function (context, myQueueItem) { 20 | context.log('JavaScript Func 2 received --> Q Item = ', myQueueItem); 21 | 22 | if (myQueueItem && myQueueItem.undo === false) { 23 | 24 | try { 25 | const work = doWork(myQueueItem.funcRes); 26 | const updatedMsg = ChainQMsg.updateChainQMsg(myQueueItem, work, "Func2"); 27 | 28 | // write to Azure Q to be picked up by next function 29 | context.bindings.outputQueueItem = updatedMsg; 30 | } 31 | catch (e) { 32 | // log error 33 | // consider undoing anything in this function (if needed) 34 | 35 | myQueueItem.undo = true; 36 | // write to Azure Q to undo prev function 37 | context.bindings.errorQueueItem = myQueueItem; 38 | } 39 | } 40 | else if (myQueueItem && myQueueItem.undo === true) { 41 | const lastFunc = myQueueItem.history[myQueueItem.history.length - 1]; 42 | 43 | if (lastFunc.from === "Func2") { 44 | const undoRes = undoWork(myQueueItem.funcRes); 45 | if (undoRes === lastFunc.input.input) { 46 | context.log('Func2 undo successful! undoRes = ' + undoRes); 47 | 48 | //clear current func history after undo 49 | myQueueItem.history.pop(); 50 | myQueueItem.funcRes = lastFunc.input; 51 | // write to Azure Q to undo prev function 52 | context.bindings.errorQueueItem = myQueueItem; 53 | } 54 | 55 | } 56 | } 57 | 58 | 59 | context.done(); 60 | }; -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func2/readme.md: -------------------------------------------------------------------------------- 1 | # QueueTrigger - JavaScript 2 | 3 | The `QueueTrigger` makes it incredibly easy to react to new Queues inside of Azure Queue Storage. This sample demonstrates a simple use case of processing data from a given Queue using C#. 4 | 5 | ## How it works 6 | 7 | For a `QueueTrigger` to work, you provide a path which dictates where the queue messages are located inside your container. 8 | 9 | ## Learn more 10 | 11 | Documentation -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func2/sample.dat: -------------------------------------------------------------------------------- 1 | sample queue data -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func3/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "name": "myQueueItem", 6 | "type": "queueTrigger", 7 | "direction": "in", 8 | "queueName": "outqueue3", 9 | "connection": "AzureWebJobsDashboard" 10 | }, 11 | { 12 | "type": "queue", 13 | "name": "errorQueueItem", 14 | "queueName": "outqueue2", 15 | "connection": "AzureWebJobsDashboard", 16 | "direction": "out" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func3/index.js: -------------------------------------------------------------------------------- 1 | const ChainQMsg = require('../ChainQMsg').ChainQMsg; 2 | 3 | // 4 | function doWork(funcRes) { 5 | const res = funcRes.input * 2; 6 | 7 | return res; 8 | } 9 | 10 | // 11 | function undoWork(input) { 12 | const res = input / 2; 13 | 14 | return res; 15 | } 16 | 17 | 18 | module.exports = function (context, myQueueItem) { 19 | context.log('JavaScript Func 3 received --> Q Item = ', myQueueItem); 20 | if (myQueueItem && myQueueItem.undo === false) { 21 | 22 | try { 23 | 24 | const randVal = Math.random() * 100; 25 | if (randVal > (100 - myQueueItem.funcRes.errorratio)) { 26 | throw { 27 | "error" : "Bad luck on Function 3 randVal=" + randVal + " error ratio= " +myQueueItem.funcRes.errorratio, 28 | "chainMsg" : myQueueItem 29 | }; 30 | } 31 | const work = doWork(myQueueItem.funcRes); 32 | const updatedMsg = ChainQMsg.updateChainQMsg(myQueueItem, work, "Func3"); 33 | 34 | //work for Func3 is complete 35 | context.log('JavaScript Func 3 completed ', workDone); 36 | } 37 | catch (e) { 38 | // log error 39 | // consider undoing anything in this function (if needed) 40 | 41 | myQueueItem.undo = true; 42 | // write to Azure Q to undo prev function 43 | context.bindings.errorQueueItem = myQueueItem; 44 | } 45 | 46 | //do something to complete the chain... 47 | } 48 | context.done(); 49 | }; -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func3/readme.md: -------------------------------------------------------------------------------- 1 | # QueueTrigger - JavaScript 2 | 3 | The `QueueTrigger` makes it incredibly easy to react to new Queues inside of Azure Queue Storage. This sample demonstrates a simple use case of processing data from a given Queue using C#. 4 | 5 | ## How it works 6 | 7 | For a `QueueTrigger` to work, you provide a path which dictates where the queue messages are located inside your container. 8 | 9 | ## Learn more 10 | 11 | Documentation -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/Func3/sample.dat: -------------------------------------------------------------------------------- 1 | sample queue data -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/TriggerFunc/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req" 9 | }, 10 | { 11 | "type": "http", 12 | "direction": "out", 13 | "name": "res" 14 | }, 15 | { 16 | "type": "queue", 17 | "name": "outputQueueItem", 18 | "queueName": "outqueue1", 19 | "connection": "AzureWebJobsDashboard", 20 | "direction": "out" 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/TriggerFunc/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ChainQMsg = require('../ChainQMsg').ChainQMsg; 4 | 5 | module.exports = function (context, req) { 6 | context.log('JavaScript HTTP trigger function processed a request.'); 7 | 8 | if (req.query.number && req.query.errorratio ) { 9 | 10 | const inputNumber = parseInt(req.query.number, 10); 11 | const inputErrorRatio = parseInt(req.query.errorratio, 10); 12 | 13 | if (inputNumber != NaN && inputErrorRatio != NaN) { 14 | const msg = ChainQMsg.newChainQMsg(inputNumber, inputErrorRatio); 15 | 16 | // write to Azure Q to be picked up by next function 17 | context.bindings.outputQueueItem = msg; 18 | 19 | context.res = { 20 | // status: 200, /* Defaults to 200 */ 21 | body: "Hello " + inputNumber 22 | }; 23 | } 24 | else { 25 | context.res = { 26 | status: 422, 27 | body: "Please pass a number value and errorratio on the query string or in the request body" 28 | }; 29 | 30 | } 31 | } 32 | else { 33 | context.res = { 34 | status: 400, 35 | body: "Please pass a number value and errorratio on the query string or in the request body" 36 | }; 37 | } 38 | context.done(); 39 | }; -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/TriggerFunc/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure" 3 | } -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/host.json: -------------------------------------------------------------------------------- 1 | {"id":"491ac3e8ec2e448bbd948242f45d023b"} -------------------------------------------------------------------------------- /FunctionsChainingTransaction/src/Azure/JS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "funchain", 3 | "version": "1.0.0", 4 | "description": "Function Chain with Transactions", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Yochay Kiriaty", 10 | "license": "ISC", 11 | "dependencies": { 12 | "uuid": "^3.0.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Serverless Design Patterns 2 | This repo contains a collections of common Serverless Design Patterns. 3 | 4 | Partial list of common Serverless patterns (not all are implemented yet): 5 | 6 | 1. Function Chaining 7 | 2. Function Chaining with Rollback (transaction) 8 | 3. ASync HTTP (HTTP 202) 9 | 4. Fanout (Parallel) 10 | 5. Fanout + Fan-in 11 | 6. Long Running Function 12 | 7. Long Running Function with Timeout 13 | 8. Manual interaction with Timeout 14 | 15 | The goal is to create examples of Serverless Patterns including some basic theory and documentation about the patterns and common use cases. 16 | --------------------------------------------------------------------------------