Giter Club home page Giter Club logo

openwhisk-runtime-dotnet's Introduction

Apache OpenWhisk runtimes for .NET

License Continuous Integration

Give it a try today

Create a C# project called Apache.OpenWhisk.Example.Dotnet:

dotnet new classlib -n Apache.OpenWhisk.Example.Dotnet -lang "C#"
cd Apache.OpenWhisk.Example.Dotnet

Install the Newtonsoft.Json NuGet package as follows:

dotnet add package Newtonsoft.Json -v 13.0.1

Now create a file called Hello.cs with the following content:

using System;
using Newtonsoft.Json.Linq;

namespace Apache.OpenWhisk.Example.Dotnet
{
    public class Hello
    {
        public JObject Main(JObject args)
        {
            string name = "stranger";
            if (args.ContainsKey("name")) {
                name = args["name"].ToString();
            }
            JObject message = new JObject();
            message.Add("greeting", new JValue($"Hello, {name}!"));
            return (message);
        }
    }
}

Publish the project as follows:

dotnet publish -c Release -o out

Zip the published files as follows:

cd out
zip -r -0 helloDotNet.zip *

Create the action

wsk action update helloDotNet helloDotNet.zip --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --kind dotnet:6.0

For the return result, not only support dictionary but also support array

So a very simple hello array function would be:

using System;
using Newtonsoft.Json.Linq;

namespace Apache.OpenWhisk.Tests.Dotnet
{
    public class HelloArray
    {
        public JArray Main(JObject args)
        {
            JArray jarray = new JArray();
            jarray.Add("a");
            jarray.Add("b");
            return (jarray);
        }
    }
}

And support array result for sequence action as well, the first action's array result can be used as next action's input parameter.

So the function can be:

using System;
using Newtonsoft.Json.Linq;

namespace Apache.OpenWhisk.Tests.Dotnet
{
    public class HelloPassArrayParam
    {
        public JArray Main(JArray args)
        {
            return (args);
        }
    }
}

Changelogs

Quick Start Guides

License

Apache 2.0

openwhisk-runtime-dotnet's People

Contributors

csantanapr avatar dgrove-oss avatar falkzoll avatar indiepeeters avatar jbampton avatar kamyker avatar luke-roy-ibm avatar mrutkows avatar ningyougang avatar rabbah avatar sechunoh avatar shawnallen85 avatar style95 avatar upgle avatar woutersterp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

openwhisk-runtime-dotnet's Issues

What's the correct way to run tests against basic openwhisk and a new runtime?

Hey everyone, I'm working on getting .net6.0 working and I'm not used to gradle unfortunately - when I run it in the openwhisk-runtime-dot as gradle build I get an error about compileTestScala:

I'm running this on my ubuntu 18.04 WSL2 terminal.

my thought is that I need to get all the tests to run against the basic openwhisk repo, but when I run that I get lots of tests failing with initializationError are there any docs around about how to get the tests to build/compile/pass for the basic openwhisk repo and then how to do so for a new runtime?

Do you have to have openwhisk running in standalone mode to have the gradle build pass?

Output of dotnet runtime's gradle build

> Task :tests:compileTestScala FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':tests:compileTestScala'.
> Could not resolve all files for configuration ':tests:testCompileClasspath'.
   > Could not find org.apache.openwhisk:openwhisk-tests:1.0.0-SNAPSHOT.
     Searched in the following locations:
       - https://repo.maven.apache.org/maven2/org/apache/openwhisk/openwhisk-tests/1.0.0-SNAPSHOT/maven-metadata.xml
       - https://repo.maven.apache.org/maven2/org/apache/openwhisk/openwhisk-tests/1.0.0-SNAPSHOT/openwhisk-tests-1.0.0-SNAPSHOT.pom
       - https://repo.maven.apache.org/maven2/org/apache/openwhisk/openwhisk-tests/1.0.0-SNAPSHOT/openwhisk-tests-1.0.0-SNAPSHOT-tests.jar
       - file:/home/paul42/.m2/repository/org/apache/openwhisk/openwhisk-tests/1.0.0-SNAPSHOT/maven-metadata.xml
       - file:/home/paul42/.m2/repository/org/apache/openwhisk/openwhisk-tests/1.0.0-SNAPSHOT/openwhisk-tests-1.0.0-SNAPSHOT.pom
       - file:/home/paul42/.m2/repository/org/apache/openwhisk/openwhisk-tests/1.0.0-SNAPSHOT/openwhisk-tests-1.0.0-SNAPSHOT-tests.jar
     Required by:
         project :tests

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 25s
26 actionable tasks: 25 executed, 1 up-to-date

lots of errors in the test file for the gradle build in the openwhisk repo:
java.lang.AssertionError: could not determine openwhisk home etc.

kind 'dotnet:2.1' not in Set

Hello,

I'm running the tutorial off your README and seeing the following error:

wsk action create helloDotNet helloDotNet.zip --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --kind dotnet:2.2
error: Unable to create action 'helloDotNet': The request content was malformed:
kind 'dotnet:2.2' not in Set(php:7.1, nodejs:8, swift:3, nodejs, blackbox, java, sequence, nodejs:6, python:3, python, python:2, swift, swift:3.1.1) (code 224)
Run 'wsk --help' for usage.

I've installed openwhisk on a local openshift cluster with no errors:
oc process -f https://git.io/vpnUR | oc create -f -

Any ideas? Thanks.

Question: how to log to activations using dotnet and openwhisk?

Hey All, love openwhisk so far, I've got it running on a small 2-node vm cluster, using the helm chart, doing the examples in dotnet and having a good time so far, but noticing that I'm not getting any logs when I try wsk activation logs -l or on any of my invokes - I'm trying to do the 'conductor' docs right now so I don't know if that would affect it, but when I try a Console.Writeline() or Console.Out.Writeline() I don't see anything in the logs - is there a correct way to write logs out?

Thanks,
Paul

Action cannot load Microsoft.Extensions.DependencyInjection.Abstraction

I have a c# OpenWhisk Action:

using System;
using IHWhisk.Models;
using Newtonsoft.Json.Linq;

namespace IHWhisk
{
    public class Hello
    {
        public JObject Main(JObject args)
        {
            var handian = new Handian();

            string errorText = "";
            
            try
            {
                using var db = new IHDbContext();
                db.Handians.Add(handian);
                db.SaveChanges();
            }
            catch (Exception e)
            {
                errorText = e.Message;
            }

            var message = new JObject();
            message.Add("Content-Type", new JValue("application/json"));
            message.Add("body", new JValue($"<p>Error: {errorText}</p>"));
            return message;
        }
    }
}

which uses EF Core dependency injection to configure and access the database, like so:

using System;
using Microsoft.EntityFrameworkCore;
using IHWhisk.Models;

namespace IHWhisk
{
    public class IHDbContext : DbContext
    {
        public DbSet<Handian> Handians { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder builder)
        {
            var connectionString = "Server=#.#.#.#;Database=ih;Port=5432;User Id=postgres;Password=supersecretpassword";
            builder
                .UseNpgsql(connectionString, o
                    => o.EnableRetryOnFailure());
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder
                .HasPostgresExtension("uuid-ossp")
                .Entity<BaseEntity>(entity =>
                {
                    entity.HasIndex("Discriminator");
                    entity.Property(p => p.Uuid)
                        .HasDefaultValueSql("uuid_generate_v4()"); // All IH entities get a postgres Uuid4
                })
                .Entity<Handian>(entity => { entity.Property<DateTime>(p => p.Birthday).HasDefaultValueSql("now()"); });
        }
    }
}

which when run inside my OpenWhisk installation fails with the error:

Error: Could not load file or assembly 'Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Could not find or load a specific file. (0x80131621)

I test this Action locally by invoking it from a clean console app like so:

namespace WhiskTester
{
    class Program
    {
        static void Main(string[] args)
        {
            var ihwhisk = new IHWhisk.Hello();
            var callArgs = new JObject();
            var result = ihwhisk.Main(callArgs);
            Console.WriteLine(result);
        }
    }
}

It works when tested locally... a new record is written to the database as expected.

Things I've tried to resolve the issue:

  • Successfully performed a DB insert without EF Core, ruling out a DB misconfiguration or a problem with the NGPSQL drivers
  • Replaced NGPSQL with Microsoft's SQLite driver and replicated the issue to further rule out a NGPSQL problem
  • Verified that Microsoft.Extensions.DependencyInjection.Abstractions.dll v3.1.3 is in the zip file I am sending to OpenWhisk
  • Downgraded Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Abstractions, Microsoft.EntityFrameworkCore.Design, Microsoft.EntityFrameworkCore.Tools and Npgsql.EntityFrameworkCore.PostgreSQL to version 3.1.2. The error message now references missing Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.2.0

At this point I've reached the edge of my knowledge and would be grateful for any advice or guidance you could offer.

support init time parameters

At some point in the past we added support in OpenWhisk for init time parameters (these are “env” vars). See https://github.com/apache/openwhisk/blob/4babe39fd2dbcc900ccedb5a5e9561d301361205/tests/src/test/scala/actionContainers/BasicActionRunnerTests.scala#L125 

For backward compatibility, runtimes weren’t required to implement this. The .net 3.1 runtime doesn’t override the required function so that behavior is skipped https://github.com/apache/openwhisk-runtime-dotnet/blob/master/tests/src/test/scala/actionContainers/DotNet3_1ActionContainerTests.scala 

We should add this support to the runtime.

improve cold start times

You’d need to ask ibm :)

As an Apache project we’d love the contribution, which you could then build and push to dockerhub and use independent of the ibm lifecycle.
Originally posted by @rabbah in #22 (comment)

Didn't know it was possible but 3.1 image from docker works fine with ibm functions.

Instead of:

ibmcloud fn action update {methodName} out.zip --kind dotnet:2.2 --main {namespaceName}::{namespaceName}.{className}::{methodName} --web true

Simply run:

ibmcloud fn action update {methodName} out.zip --docker openwhisk/action-dotnet-v3.1 --main {namespaceName}::{namespaceName}.{className}::{methodName} --web true

Just letting you know :)

Remove dependency on 3rd party JSON library from next version of runtime

Based on conversation in #34 and #50...

Problem:

OpenWhisk users creating .NET actions need to add a dependency on a 3rd party JSON library (currently Newtonsoft.Json as of the dotnet:3.1 runtime) because the contract between action and runtime provides the action main function with a JObject via paramter and requires the main function to return a JObject.

Consequences:

  • This adds friction to creating an action (User: "Why do I need to use this 3rd party library?")
  • Can result in errors when the versions of the 3rd party library differ between the runtime and the action. Testing so far has found that it's okay for a runtime to use a version of Newtonsoft.Json with a higher major version than the action, but the actions don't run because of an error loading the action code for the other way around.

Potential solution:

Since the contract between runtimes and actions is really just an arbitrary map of data (as seen in the Node.js runtime instructions as https://github.com/apache/openwhisk/blob/master/docs/actions-nodejs.md where they just return { done: true } and { message: 'my message' } etc), use a map data structure for this contract. C# and other CLR languages supported by the .NET runtime like VB.NET have Dictionary for that (https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0). If the map data structure type changes between runtimes, like moving from .NET Core 3.1 to .NET 6 for example, OpenWhisk users would be instructed via documentation for the new runtime to use a different type from the standard library of the language.

That way, all versions of the runtime and every action ever created for the runtime would not depend on things that need major version updates throughout the lifecycle of a runtime (like dotnet:3.1). The runtime would control the implementation of how JSON is handled. It could choose for example between different versions of Newtonsoft.Json or even other JSON libraries like System.Text.Json whenever it wants, with the runtime versions being updated without the action implementers ever having to worry about it.

Raw requests to skip JObject conversion

Another thing that could be added to speed up large requests processing time.

Currently there is:

string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
JObject inputObject = string.IsNullOrEmpty(body) ? null : JObject.Parse(body);

It's fine for small requests but for big ones it will allocate a lot of memory and increase time to complete any function. While that code itself could be improved by reading from Stream directly using current JsonNet (more https://www.newtonsoft.com/json/help/html/Performance.htm in "Optimize Memory Usage") it would be great to somehow skip this process completely, pass httpContext.Request (instead of JObject) and let user do whatever he wants to. In addition to that instead of returning JObject that's converted to string

  await httpContext.Response.WriteResponse(200, output.ToString());
  (...)
  await response.WriteAsync(content);

function could simply return string (or Stream like in AWS Lambda to be set for Response.Body)

So basically high performance mode, in the end function definition:
public async Task<string> Main(HttpRequest request)

Why is it important? I've just notice in Azure Functions it takes almost 2500ms to simply receive 1mb json. No idea what their sdk is doing exactly but that amount of overhead seems weird to me. They also use JsonNet.

With this feature I could use for ex. https://github.com/neuecc/Utf8Json to make part of my function in OpenWhisk run ~5 times faster and allocate ~20 times less memory :).

Edit
Did few tests:

Duration of empty function receiving 1mb request:
Azure (C# - most recent production version): 2400ms
Google/Firebase (javascript): 90-170ms
IBM/OpenWhisk (C# .NET Core 2.2): ~100ms

Seeing this I will definitely use IBM/OpenWhisk instead of Azure

incorrect quick start guide

cd out
zip -r -0 helloDotNet.bin *
wsk action update helloDotNet helloDotNet.bin --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --kind dotnet:2.2

should be

cd out
zip -r -0 helloDotNet.zip *
wsk action update helloDotNet helloDotNet.zip --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --kind dotnet:2.2

If you invoke action updated with name *.bin will result:

{ 
    "error": "code must be binary (zip file)."
}

"Cannot invoke an uninitialized action." error occurs intermittently

Thanks for adding dotnet runtime to openwhisk.

I created action with sample code but sometimes errors occur when stress tests.
I debuged with console log and I found that "/run" was called before run(Run class) object is returned.

I fixed(moved) some codes and tested. Then no error occurred any more.
sechunOH#1

But I am not a dotnet programmer, so I'm not sure if the codes I fixed fits the dotnet grammar.

Is it okay if I make a pull request? can someone review it?

Unknown error

Good morning OpenWhisk. I'm trying to hook up a test action to a Postgres database like so:

var conn = new NpgsqlConnection(connectionString);
var cmd = new NpgsqlCommand("INSERT INTO base_entity (name) VALUES ('danny')", conn);
cmd.ExecuteNonQuery();

I am getting this error message:

C:\Users\dmlod>wsk -i activation logs 7c5b1161098b41239b1161098b012371
2020-04-01T10:41:48.142980549Z stdout: at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
2020-04-01T10:41:48.143031669Z stdout: at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
2020-04-01T10:41:48.143036509Z stdout: at Apache.OpenWhisk.Runtime.Common.Run.HandleRequest(HttpContext httpContext) in /app/Apache.OpenWhisk.Runtime.Common/Run.cs:line 90
2020-04-01T10:41:48.175771203Z stderr: The action did not initialize or run as expected. Log data might be missing.

Connection string is verified ok. DB is operational. OpenWhisk will run the action if I comment out the 'ExecuteNonQuery' line.

Two questions:

  1. Any idea where I've dropped the ball here?
  2. Is there a way to get a more detailed error message?

Thank you for your time and I hope you're not too bored in quarantine.

readme update

zip -r -0 helloDotNet.bin * should be zip -r -0 helloDotNet.zip *

Can't send messages to kafka

When trying to use Confluent.Kafka in order to produce messages to kafka/event streams, we get the error :

Failed to load the librdkafka native library.
    at Confluent.Kafka.Impl.LibRdKafka.Initialize(String userSpecifiedPath)
    ...

None of the librdkafka librairies packaged with Confluent.Kafka work with the current runtime
Is there a way to have one built-in the current runtime ?

Add async/await support

It should be possible to define method like this:
public Task<JObject> Main(JObject args)

That's very common definition in ASP.Net.

It's also the case in Amazon Lambdas and Azure Functions

If you are using .NET asynchronous programming, the return type can be Task and Task types and use async and await keywords.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.