azure-functions-powershell-worker: How should the PowerShell worker implement $returns (if at all)?
Background
In Azure Functions, there is a concept of “output bindings” which are essentially the output of your function. You define these outputs in the bindings section of the function.json. Here’s an example function.json for an HttpTrigger and response:
{
"disabled": false,
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
}
notice the binding Response has a direction of out.
There exists a “special” output binding called $returns which would look like this:
{
"type": "http",
"direction": "out",
"name": "$returns"
}
This, in every language that Azure Functions supports in V2, gives the user the ability to “return” the result. Rather than explicitly specifying that value X goes to the output binding of “Foo”.
For example, in C# you would normally declare outputs using the out keyword in the function definition:
function.json
{
"type": "http",
"direction": "out",
"name": "output"
}
run.cs
public static Run(string input, out string output)
{
output = "Hello World";
}
But if you want to leverage $returns you would do:
function.json
{
"type": "http",
"direction": "out",
"name": "$returns"
}
run.cs
public static Run(string input)
{
return "Hello World";
}
Note the use of the return keyword.
The problem
PowerShell is different than most languages because it can return multiple things by leveraging the Pipeline.
In addition to that, a lot of folks write to the pipeline as a way to log something.
So implementing $returns for PowerShell is strange because it’s not clear what the intended behavior should be.
The possible solutions
Solution 1: Take everything
Everything that gets thrown onto the pipeline, will be added to a list. That list will be set as the output for the output binding $returns. In addition to that, everything added to the pipeline can be logged to the host.
This idea comes from the fact that since PowerShell can “return” multiple things, a list of the things written to the pipeline would be the most “PowerShell-y” experience for $returns.
This does mean that the user would need to log using Write-Host or others instead of simply writing to the pipeline otherwise their log statements will be included in the $returns output.
Solution 2: Take one thing
Everything that gets thrown onto the pipeline will be logged, but the LAST item added to the pipeline will be the output for the output binding $returns.
This idea comes from wanting to align with other languages. It also gives the user the ability to use the pipeline for logging and “returning”.
FWIW, AWS Lambda went with this approach - so I’ve heard.
Solution 3: Take nothing
This would mean that $returns doesn’t make sense for PowerShell and the only way to specify output is by using the Push-OutputBinding command.
That said, everything added to the pipeline can be logged to the host.
About this issue
- Original URL
- State: open
- Created 6 years ago
- Comments: 24 (5 by maintainers)
Would leveraging PowerShell classes be out of the question? Explicit return, and attributes to control bindings of functions to methods. Plus in C# functions I have an explicit way to log information I want logged, and would like the same in PowerShell. Lazier approaches (return everything), and return the last thing don’t feel right to me.
Is
Pushthe correct verb here? I think it is rarely used and may lead to confusion. It implies adding to a stack where order matters. Does it in this case? Wouldn’tSet-BindingOutput -Name foo -Value barmake more sense?It should be easy to move code from one platform to another. It should be easy to move scripters from one platform to another. Wherever possible, code should behave the same way wherever it runs. Moving a working script to Functions should largely be a matter of copy/paste. So Solution 1.
I like the notion that all the output in the function gets logged, and I’m guessing to the trace console, and no extra work on my part I can expect the last line to be returned to the caller.
I’m guessing a majority of functions can leverage that. Most of the http triggers I’ve built, I emit info to the pipeline for logging/tracing and then then the last statement I have is
$result > $res.For that pattern, my code wouldn’t really change.
I’d like to play with it a bit, get a better feel.
Every single time I’ve used “write-output” for logging, I’ve ending up regretting it.
Just say no.
However, returning tuples from functions is useful, extremely useful. I would be very disappointed to see that capability gone from any implementation (I’ve taken to commonly using something I first saw in golang: $ret, $err = function-call).
So I vote for Solution 1.