GithubHelp home page GithubHelp logo

microsoft / ambrosia Goto Github PK

View Code? Open in Web Editor NEW
418.0 35.0 49.0 7.3 MB

Robust Distributed Programming Made Easy and Efficient

Home Page: https://microsoft.github.io/AMBROSIA/

License: Other

Shell 1.75% C# 58.55% PowerShell 1.24% Batchfile 0.13% Makefile 0.10% C 2.40% Dockerfile 0.30% TypeScript 35.43% JavaScript 0.10%

ambrosia's Introduction

Ambrosia: Robust Distributed Programming Made Easy and Efficient

Windows Build (netcore3.1): Windows Core Build Status

Windows Build (netframework 461): Windows Framework Build Status

Linux Build (netcore3.1): Linux Build Status

Node JS (netcore3.1): NodeJS Core Build Status

Node JS (netframework 461): NodeJS Framework Build Status

Gitter

Ambrosia is a programming language independent approach for authoring and deploying highly robust distributed applications. Ambrosia dramatically lowers development and deployment costs and time to market by automatically providing recovery and high availability.

Today's datacenter oriented applications, which include most popular services running in the cloud today, are composed of highly complex, distributed software stacks. For instance, they typically incorporate Event Hub or Kafka to robustly journal input and interactions for recoverability, log important information to stores like Azure blobs for debuggability, and use extremely expensive mechanisms like distributed transactions, and stateless functions with distributed persistent back-ends, in order to ensure exactly once execution of service code.

In contrast, Ambrosia automatically gives programmers recoverability, high availability, debuggability, upgradability, and exactly once execution, without requiring developers to weave together such complex systems, or use overly expensive mechanisms.

To learn more about Ambrosia's implementation and performance you can read our VLDB paper.

We invite developers wishing to build on or contribute to AMBROSIA to join our gitter community.

Table of Contents

AMBROSIA Concepts

Virtual Resiliency

Virtual Resiliency is a mechanism in a (possibly distributed) programming and execution environment, typically employing a log, which exploits the replayably deterministic nature and serializability of an application to automatically mask failure.

We use the term virtual resiliency to describe the mechanism in AMBROSIA that allows programmers to write their applications in a failure oblivious way, removing the need for application writers to write logic for recovery or state protection. Data processing systems, which typically express their queries in SQL variants, have provided their query writers virtual resiliency for decades. Map-reduce systems, which don’t necessarily use SQL, also provide this capability. Note that in all these cases, this feature leverages the ability to deterministically replay, like AMBROSIA.

Deterministic Replayability

In order to achieve virtual resiliency through AMBROSIA, applications must uphold the following contract: from some initial state, any execution of the same requests in the same order results in both the same final state, as well as the same outgoing requests in the same order.

Immortals

The basic building blocks of AMBROSIA are Immortals, reliable distributed objects that communicate through RPCs. An Immortal defines a set of persistent state and a set of RPC handlers that operate on that state. An instance of an Immortal is a named entity that maintains state and executes RPC handlers according to the Immortal's definition. An AMBROSIA application often has multiple instances of the same Immortal; for example, an application may define a single "job" Immortal for running a data-processing job and run multiple instances of that job operating on different data sets.

How it works

The figure below outlines the basic architecture of an AMBROSIA application, showing two communicating AMBROSIA services, called Immortals. The inner boxes in the figure represent code which can run in either 2 separate processes, or in the case of C#, can run in one integrated process. Each instance of an Immortal exists as a software object and thread of control running inside of the application process. An Immortal instance communicates with other Immortal instances through the Immortal Coordinator, which durably logs the instance's RPCs and encapsulates the low-level networking required to send RPCs. The position of requests in the log determines the order in which they are submitted to the application process for execution and then re-execution upon recovery.

Ambrosia Architecture

In addition, the language specific AMBROSIA binding provides a state serializer. To avoid replaying from the start of the service during recovery, the Immortal Coordinator occasionally checkpoints the state of the Immortal, which includes the application state. The way this serialization is provided can vary from language to language, or even amongst bindings for the same language.

Features

Here is a list of features that AMBROSIA provides to application developers and deployers:

  • Define a new service to run on AMBROSIA
  • Deploy services on AMBROSIA
  • Debug service instance
  • Active Active
  • Live Upgrades, Test Upgrades
  • RPC
  • Asynchronous RPC (alpha)

Quick start for application developers

Start with one of our samples to get a service up and running on AMBROSIA.

Quick start for AMBROSIA contributors

Build from source

Build the Ambrosia Immortal coordinator and C# client code generator with this Bash script:

./build_dotnetcore_bindist.sh

Given a .NET Core SDK, this will work on Windows, Mac OS, or Linux. After that, you have an AMBROSIA binary distribution built inside the ./bin directory within your working copy.

Also check out our contributing guide.

Reference

Dependencies

AMBROSIA currently requires an Azure subscription to write its logs to replicated storage. In the future, we anticipate abstracting this component out to be able to use other storage options for logs.

Language Support

AMBROSIA currently supports C# on both .NET Core and .NET Framework. As of the 2.0.0.0 release, AMBROSIA also supports Node.js using TypeScript. We hope to add support for other languages in the future.

Usage

Usage: dotnet Ambrosia.dll RegisterInstance [OPTIONS]
Options:
  -i, --instanceName=VALUE         The instance name [REQUIRED].
  -rp, --receivePort=VALUE         The service receive from port [REQUIRED].
  -sp, --sendPort=VALUE            The service send to port. [REQUIRED]
  -l, --log=VALUE                  The service log path.
  -cs, --createService=VALUE       [A - AutoRecovery | N - NoRecovery | Y -
                                     AlwaysRecover].
  -ps, --pauseAtStart              Is pause at start enabled.
  -npl, --noPersistLogs            Is persistent logging disabled.
  -lts, --logTriggerSize=VALUE     Log trigger size (in MBs).
  -aa, --activeActive              Is active-active enabled.
  -cv, --currentVersion=VALUE      The current version #.
  -uv, --upgradeVersion=VALUE      The upgrade version #.
  -h, --help                       show this message and exit
Usage: dotnet Ambrosia.dll AddReplica [OPTIONS]
Options:
  -r, --replicaNum=VALUE           The replica # [REQUIRED].
  -i, --instanceName=VALUE         The instance name [REQUIRED].
  -rp, --receivePort=VALUE         The service receive from port [REQUIRED].
  -sp, --sendPort=VALUE            The service send to port. [REQUIRED]
  -l, --log=VALUE                  The service log path.
  -cs, --createService=VALUE       [A - AutoRecovery | N - NoRecovery | Y -
                                     AlwaysRecover].
  -ps, --pauseAtStart              Is pause at start enabled.
  -npl, --noPersistLogs            Is persistent logging disabled.
  -lts, --logTriggerSize=VALUE     Log trigger size (in MBs).
  -aa, --activeActive              Is active-active enabled.
  -cv, --currentVersion=VALUE      The current version #.
  -uv, --upgradeVersion=VALUE      The upgrade version #.
  -h, --help                       show this message and exit
Usage: dotnet Ambrosia.dll DebugInstance [OPTIONS]
Options:
  -i, --instanceName=VALUE         The instance name [REQUIRED].
  -rp, --receivePort=VALUE         The service receive from port [REQUIRED].
  -sp, --sendPort=VALUE            The service send to port. [REQUIRED]
  -l, --log=VALUE                  The service log path.
  -c, --checkpoint=VALUE           The checkpoint # to load.
  -cv, --currentVersion=VALUE      The version # to debug.
  -tu, --testingUpgrade            Is testing upgrade.
  -h, --help                       show this message and exit

Secure communication between services

Read about how to secure communications between distributed components deployed on AMBROSIA here.

ambrosia's People

Contributors

badrishc avatar cimryan avatar cmeiklejohn avatar darrenge avatar espadrine avatar jmfaleiro avatar jongolddb avatar jskulavik avatar kant avatar lovettchris avatar microsoft-github-policy-service[bot] avatar mpeina avatar nlebeck avatar raghoshmsft avatar rich-msr avatar rrnewton avatar saj9191 avatar sebastianburckhardt avatar talzaccai 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  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  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  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  avatar  avatar  avatar  avatar  avatar  avatar

ambrosia's Issues

Immortals can't contain properties

Immortals can't contain properties because of a bug in CopyFromDeserializedImmortal.

The function gets a "MemberTypes.Property", and then immediately tries to cast it to a (FieldInfo).

if (memberInfo.MemberType == MemberTypes.Field || memberInfo.MemberType == MemberTypes.Property)
{
var fi = (FieldInfo)memberInfo;
var v = fi.GetValue(otherImmortal);
fi.SetValue(this, v);
}

run_helloworld_server.sh of HelloWorld fail

The input arguments of Server were changed in the commit b500fe12e6ef0ce43f3401972ececfccaa962ca. But the run_helloworld_server.sh was not updated. Attached the patch file

Index: Samples/HelloWorld/run_helloworld_server.sh
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- Samples/HelloWorld/run_helloworld_server.sh	(date 1560293594000)
+++ Samples/HelloWorld/run_helloworld_server.sh	(date 1560500575000)
@@ -35,5 +35,5 @@
 set -x
 AMBROSIA_INSTANCE_NAME=$SERVERNAME AMBROSIA_IMMORTALCOORDINATOR_PORT=$CRAPORT2 \
 COORDTAG=CoordServ AMBROSIA_IMMORTALCOORDINATOR_LOG=$slog \
-  runAmbrosiaService.sh dotnet Server/publish/Server.dll $SERVERNAME 
+  runAmbrosiaService.sh dotnet Server/publish/Server.dll $PORT4 $PORT3 $SERVERNAME 
 set +x

Dead?

So is Ambrosia another dead and abandoned project by Microsoft?

Messages get out of sync

I'm getting this exception in Immortal.cs using latest bits:

 var s = String.Format("Illegal leading byte in message: {0}", firstByte);

But if I revert this recent change:

int commitID = await this._ambrosiaReceiveFromStream.ReadIntFixedAsync(cancelTokenSource.Token);
bytesToRead = await this._ambrosiaReceiveFromStream.ReadIntFixedAsync(cancelTokenSource.Token);
long checkBytes = await this._ambrosiaReceiveFromStream.ReadLongFixedAsync(cancelTokenSource.Token);
long writeSeqID = await this._ambrosiaReceiveFromStream.ReadLongFixedAsync(cancelTokenSource.Token);

to this, then everything works fine:

int commitID = this._ambrosiaReceiveFromStream.ReadIntFixed();
bytesToRead = this._ambrosiaReceiveFromStream.ReadIntFixed();
long checkBytes = this._ambrosiaReceiveFromStream.ReadLongFixed();
long writeSeqID = this._ambrosiaReceiveFromStream.ReadLongFixed();

Code Gen generated Proxy_*Immortal.cs contains duplicated methods when *Immortal interface uses overrided methods

In the case below, I have an interface InventoryEntityMonitorImmortal, it contains methods named Subscribe and UnSubscribe using overriding.

And this caused the Code Gen generated Proxy_InventoryEntityMonitorImmortal to have duplicated definitions of method Subscribe_ReturnValue(byte[] buffer, int cursor) which eventually caused compile errors.

private object
Subscribe_ReturnValue(byte[] buffer, int cursor)
{
// buffer will be an empty byte array since the method Subscribe returns void
// so nothing to read, just getting called is the signal to return to the client
return this;
}

InventoryEntityMonitorImmortal.txt
Proxy_InventoryEntityMonitorImmortal.txt

Assembly version numbers

It would be very handy for debugging if you added version numbers to your assemblies that match the nuget release number... for example, I installed release 1.0.11, but the assembly says 1.0.0.0.

image

Add an explicit ipv4/ipv6 switch for ImmortalCoord<->App local communication

Right now there are various places where it's assumed that Windows=>ipv6 and Linux=>ipv4 for the communication between the app process and ImmortalCoordinator process.

These should not be conflated. Instead, there should be an explicit flag somewhere for how the coordinator and app communicate. Indeed, perhaps it should be over multiple interfaces (not just localhost) or offer other configurability.

Any configurability for ImmortalCoordinator faces the question of whether it comes as a command-line parameter to the coordinator (late), or as part of the Ambrosia RegisterInstance upload to the metadata table in the cloud (early).

It's a discussion that deserves it's own issue -- shouldn't these ultimately be fungible? Config parameters could be put in either place. Adding an ipv4/v6 switch could go in one place or the other for the time being.

Need a way for server to "forget" a I*ClientImmortalProxy

I have an app where clients come and go but the server lives on. Clients register for call backs, then unregister. This means the server needs a way to forget the client immortal proxy. According to Jonathan this is a "todo".

Samples: ActiveActive windows throwing exception

When I come to the following command:
To run the Immortal Coordinator for the first server replica

cd %AMBROSIATOOLS%\x64\Release\netcoreapp2.0
dotnet ImmortalCoordinator.dll -instanceName=server -port=3500 -r=1

I am getting the following error:

Starting CRA Worker instance [http://github.com/Microsoft/CRA]
   Instance Name: server1
   IP address: 10.9.137.26
   Port: 3500
   Azure connection string: my_conn_str
   Secure network connections: Disabled
Disabling dynamic assembly loading
Enabling sideload for vertex: ambrosia (Ambrosia.AmbrosiaRuntime)
Ready ...
Logs directory: C:\logs\
INFO: Unable to initialize vertex server. Check if runtime is compatible (uploaded vertex and worker should be same .NET runtime). Exception:
System.AggregateException: One or more errors occurred. (An attempt was made to access a socket in a way forbidden by its access permissions) ---> System.Net.Sockets.SocketException: An attempt was made to access a socket in a way forbidden by its access permissions
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at Ambrosia.AmbrosiaRuntime.SetupLocalServiceStreams() in D:\a\1\s\Ambrosia\Ambrosia\Program.cs:line 2156
   at Ambrosia.AmbrosiaRuntime.PrepareToRecoverOrStart() in D:\a\1\s\Ambrosia\Ambrosia\Program.cs:line 2212
   at Ambrosia.AmbrosiaRuntime.<RecoverOrStartAsync>d__91.MoveNext() in D:\a\1\s\Ambrosia\Ambrosia\Program.cs:line 2254
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
   at Ambrosia.AmbrosiaRuntime.Initialize(Int32 serviceReceiveFromPort, Int32 serviceSendToPort, String serviceName, String serviceLogPath, Nullable`1 createService, Boolean pauseAtStart, Boolean persistLogs, Boolean activeActive, Int64 logTriggerSizeMB, String storageConnectionString, Int64 currentVersion, Int64 upgradeToVersion) in D:\a\1\s\Ambrosia\Ambrosia\Program.cs:line 3845
   at Ambrosia.AmbrosiaRuntime.Initialize(Object param) in D:\a\1\s\Ambrosia\Ambrosia\Program.cs:line 3742
   at CRA.ClientLibrary.CRAClientLibrary.<InitializeVertexAsync>d__40.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at CRA.ClientLibrary.CRAClientLibrary.<LoadVertexAsync>d__38.MoveNext()
---> (Inner Exception #0) System.Net.Sockets.SocketException (0x80004005): An attempt was made to access a socket in a way forbidden by its access permissions
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at Ambrosia.AmbrosiaRuntime.SetupLocalServiceStreams() in D:\a\1\s\Ambrosia\Ambrosia\Program.cs:line 2156
   at Ambrosia.AmbrosiaRuntime.PrepareToRecoverOrStart() in D:\a\1\s\Ambrosia\Ambrosia\Program.cs:line 2212
   at Ambrosia.AmbrosiaRuntime.<RecoverOrStartAsync>d__91.MoveNext() in D:\a\1\s\Ambrosia\Ambrosia\Program.cs:line 2254<---

Windows 10

HelloWorld doc suggestion

Pulled my hair out on the "dotnet Ambrosia.dll RegisterInstance -i=server -rp=2000 -sp=2001 -l=C:\logs" getting "The CRA instance appears to be down. Restart it and this vertex will be instantiated automatically" until I realized the next paragraph says this is expected.

I would have seen it if you put the expected error in triple back tick code block.

AmbrosioaCS Codegen not running on dotnet core build - XML parse error

It gives this error:

root@585edf0692a3:/ambrosia/InternalImmortals/PerformanceTestInterruptible# 
$ AmbrosiaCS CodeGen -a IJob/bin/Release/netcoreapp2.0/linux-x64/IJob.dll -a API/bin/Release/netcoreapp2.0/linux-x64/ServerAPI.dll -o PTIAmbrosiaGeneratedAPI -f netcoreapp2.0 -b ./CodeGenDependencies/netcoreapp2.0/

Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'Microsoft.CodeAnalysis, Version=2.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
   at Ambrosia.Program.RunCodeGen()
   at Ambrosia.Program.Main(String[] args) in /ambrosia/Clients/CSharp/AmbrosiaCS/Program.cs:line 32
Aborted

2.7 is referred to in our top level nuspec:

Ambrosia.nuspec:      <dependency id="Microsoft.CodeAnalysis.CSharp.Scripting" version="2.7.0" />

I don't really know how that's used but I'm guessing it's only for building a nuget package, not for our dotnet publish-based scripted builds. The directory we publish to (bin within the working directory, or /ambrosia/bin within the Docker containers) ends up with a copy of the 2.6 DLL not the 2.7 one.

@jongoldDB mentioned that something actually needed a specific (2.6 or 2.7) version of this library and that @mike-barnett may know something about it?

@darrenge - this is the blocking bug that is keeping Linux CI from working on Master. (ryan/temp branch only works because it is held back against an older version of the codegen, and therefore missing the changes that cause this breakage, whatever those were.)

issue in StreamingDemo: Most tweets are filtered

In StreamingDemo, most of the tweet are filtered out as language always equal to null. Thus no tweet is processed. Nothing displayed on the dashboard.

I fix it by removing an if-condition in TwitterObervable.cs

Index: Samples/StreamingDemo/TwitterObservable/TwitterObservable.cs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- Samples/StreamingDemo/TwitterObservable/TwitterObservable.cs	(revision be8fb287b40b88c111a4c40461eab1216888cfdc)
+++ Samples/StreamingDemo/TwitterObservable/TwitterObservable.cs	(date 1562899451000)
@@ -113,7 +113,7 @@
 
                             // filter out tweets we don't care about: non-english tweets or deleted tweets
                             if ((jObject["delete"] != null) ||
-                                (language != "en") ||
+                                //(language != "en") ||
                                 (topic == "Unknown"))
                                 continue;

Support for Enums?

I added an enum to my interface to better describe some error code, but the code generator resulted in invalid code:

using System;
using System.Runtime.Serialization;
namespace PropertyBagImmortalInterfaces {
public struct PropertyBagResult
{
    public Int32 value__;
    public PropertyBagResult Success;
    public PropertyBagResult KeyNotFound;
    public PropertyBagResult KeyExists;
    public PropertyBagResult ValueNotChanged;
}
}

1>PropertyBagResult.cs(7,30,7,37): error CS0523: Struct member 'PropertyBagResult.Success' of type 'PropertyBagResult' causes a cycle in the struct layout

GetLocalIPAddress is not general enough.

ImmortalCoordinator has this method GetLocalIPAddress which is handy, but not correct in the case where a computer has multiple ethernet interfaces (e.g. wired and wireless). In this case the user may want to specify which interface to use since they know which one is connected to the right network. You could also provide a better default which tests all available interfaces to figure out which one can reach Azure storage.

Note that CRA gets it right with CRA.Worker.exe where "An optional third parameter can be used to provide an explicit IP address."

Ambrosia RegisterInstance catches exceptions and returns without error code

This is me running a script locally on WSL under Windows:

[rrnewton@t-rynewt-Z4 ~/work/AMBROSIA/InternalImmortals/NativeService (ryan/temp)]
$ ./run_test_in_one_container.sh
Using AZURE_STORAGE_CONN_STRING = DefaultEndpointsProtocol=xxxxxxxx
+ PORT1=50001
+ PORT2=50002
+ PORT3=50003
+ PORT4=50004
+ CLIENTNAME=native1
+ SERVERNAME=native2
+ Ambrosia RegisterInstance -i native1 --rp 50001 --sp 50002 -l /ambrosia_logs/
Error trying to upload service. Exception: Method not found: 'Remote.Linq.Expressions.Expression Remote.Linq.ExpressionTranslator.ToRemoteLinqExpression(System.Linq.Expressions.Expression, Aqua.TypeSystem.ITypeInfoProvider, System.Func`2<System.Linq.Expressions.Expression,Boolean>)'.
+ Ambrosia RegisterInstance -i native2 --rp 50003 --sp 50004 -l /ambrosia_logs/
Error trying to upload service. Exception: Method not found: 'Remote.Linq.Expressions.Expression Remote.Linq.ExpressionTranslator.ToRemoteLinqExpression(System.Linq.Expressions.Expression, Aqua.TypeSystem.ITypeInfoProvider, System.Func`2<System.Linq.Expressions.Expression,Boolean>)'.
+ AMBROSIA_INSTANCE_NAME=native1
+ AMBROSIA_IMMORTALCOORDINATOR_PORT=1500
+ runAmbrosiaService.sh ./service_v4.exe 0 native2 50001 50002 24 1 20

I have installed the dotnet CLI in this Linux environment, and I have built the AMBROSIA binary distribution in that same environment (dotnet publish). And nevertheless the above "Method not found" error occurs at runtime.

The second problem is that the error is non-fatal. Ambrosia RegisterInstance hits the exception but then the process returns 0 so that the calling script keeps going, when it shouldn't!

System Info

$ dotnet --version
2.1.403
$ bash --version
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
...
$ uname -a
Linux t-rynewt-Z4 4.4.0-17763-Microsoft #55-Microsoft Sat Oct 06 18:05:00 PST 2018 x86_64 x86_64 x86_64 GNU/Linux

To Reproduce

git clone [email protected]:Microsoft/AMBROSIA.git
cd AMBROSIA
git checkout 821ae2b3dba78714de5d9e9f8d4b16b1ba717b78
./build_dotnetcore_bindist.sh
export PATH=$PATH:`pwd`/bin
cd InternalImmortals/NativeService
make
./run_test_in_one_container.sh

NuGet import fails

I am trying to install the Ambrosia NuGet package into my project, but the install fails saying

NU1701: Package 'AmbrosiaLibCS 1.0.11' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETStandard,Version=v2.0'. This package may not be fully compatible with your project.
Package restore failed. Rolling back package changes for 'DurableTask.EventSourced'.

Does that mean I cannot use Ambrosia for a .NETStandard project? What are the supported project types?

ImmortalCoordinator can't yet run in ambrosia image instead of ambrosia-dev

In ambrosia-dev things work fine, but in the image that contains only the binaries (ambrosia/bin), I'm seeing this error when I start the coordinator:

Starting CRA Worker instance [http://github.com/Microsoft/CRA]
   Instance Name: native10
   IP address: 172.17.0.2
   Port: 1500
   Azure connection string: xxxxxxxx
   Secure network connections: Disabled
Disabling dynamic assembly loading
Enabling sideload for vertex: ambrosia (Ambrosia.AmbrosiaRuntime)

Unhandled Exception: System.AggregateException: One or more errors occurred. (The type initializer for 'System.Net.Http.CurlHandler' threw an exc

eption.) ---> System.TypeInitializationException: The type initializer for 'System.Net.Http.CurlHandler' threw an exception. ---> System.TypeInit

ializationException: The type initializer for 'Http' threw an exception. ---> System.TypeInitializationException: The type initializer for 'HttpI

nitializer' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'System.Net.Http.Native': The specified module or one of its

 dependencies could not be found.
 (Exception from HRESULT: 0x8007007E)
   at Interop.Http.GetSslVersionDescription()
   at Interop.HttpInitializer..cctor()
   --- End of inner exception stack trace ---
   at Interop.Http..cctor()
   --- End of inner exception stack trace ---
   at Interop.Http.GetSupportedFeatures()
   at System.Net.Http.CurlHandler..cctor()
   --- End of inner exception stack trace ---
   at System.Net.Http.CurlHandler..ctor()
   at System.Net.Http.HttpClientHandler..ctor()
   at Microsoft.WindowsAzure.Storage.Auth.Protocol.StorageAuthenticationHttpHandler.<>c.<.cctor>b__9_0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.WindowsAzure.Storage.Shared.Protocol.HttpClientFactory.<>c.<.cctor>b__3_0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Lazy`1.CreateValue()
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.<ExecuteAsyncInternal>d__4`1.MoveNext()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
   at CRA.ClientLibrary.VertexTableManager.RegisterInstance(String instanceName, String address, Int32 port)
   at CRA.ClientLibrary.CRAWorker.Start()
   at CRA.Worker.Program.Main(String[] args) in /ambrosia/ImmortalCoordinator/Program.cs:line 101
Aborted```

As you can see that happens even when running it inside the directory *with* all those dependency dll's that `dotnet publish` put there.  

UNKNOWN BYTE: 101!!

Sometimes while running my distributed property bag test I get this error on the server:

UNKNOWN BYTE: 101!!
Error sending partial page, checking page integrity: Illegal leading byte in message
UNKNOWN BYTE: 101!!

Remaining fixes needed to CI on AKS

With PR #16, automatic CI on AKS is enabled, with PerformanceTestInterruptible running between two pods of a Kubernetes cluster. However, there are two limitations with how it is currently set up:

  • The test is currently running the ambrosia/ambrosia-perftest public docker image, which is wrong, it should test the version of PerformanceTestInterruptible that is contained in the given commit of the AMBROSIA repo. It's testing the latest version of the AKS scripts, but not the latest version of PTI itself.
  • The test currently cannot fully reprovision the Azure resources. It runs fine when the resources are already there (idempotent) but cannot create each of them. That required pre-population by a local run of the script.

Both of these problems are authentication related. The ADO pipeline needs to authenticate with Dockerhub if it's going to execute a docker push. I allocated the ambrosia/ambrosia-ci-test repository for just this purpose, but I ran out of time before figuring out the ADO->Dockerhub auth.

The second problem is related to the permissions and powers of the CI user vis a vis the Azure CLI calls used in the AKS-scripts directory. The AKS-scripts/run-end-to-end* will provision everything from scratch for a local user. But if the resource group is wiped away, then it will fail to provision everything inside a CI job.

(Overcoming that is even more challenging if one wants to push to a private Azure Container Registry instead of public dockerhub.)

AmbrosiaCS.exe crashes due to missing AmbrosiaLibCS DLL in 1.0.1.0 Windows release

When I run the version of AmbrosiaCS.exe included in the 1.0.1.0 Windows binary release, it crashes with the following exception:

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'AmbrosiaLibCS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at Ambrosia.Utilities.GetMethodInformation(MethodInfo m, UInt32 i)
   at System.Linq.Enumerable.<SelectIterator>d__5`2.MoveNext()
   at Ambrosia.ProxyInterfaceGenerator.TransformText()
   at Ambrosia.Program.RunCodeGen()
   at Ambrosia.Program.Main(String[] args)

It looks like the problem is that the AmbrosiaLibCS.dll file is not included in the 1.0.1.0 Windows ZIP file, whereas that DLL was included in the previous releases. I think this particular crash is because the codegen program is trying to use the ImpulseHandlerAttribute type defined in AmbrosiaLibCS.

Recovery fails in Windows Forms app with ImpulseHandler RPCs

When running the Windows Forms version of GraphicalApp in the UWPExample solution (the Windows Forms version of the collaborative drawing app), recovery consistently fails due to a failed assert. The assert in question is on line 551 of Program.cs in the Ambrosia project (the code is Debug.Assert(curBuffer.LowestSeqNo <= firstSeqNo); in the ReplayFromAsync() method).

I'm not sure if there's a bug in Ambrosia, or if I'm doing something wrong with ImpulseHandlers in the UWPExample code. If there's a bug in Ambrosia, we definitely want to fix it, but if I'm doing something wrong, it would still be good to identify the mistake so that we can address it in our tutorials/documentation.

Repro steps

  1. Build the UWPExample solution, run the codegen scripts, etc.
  2. Run an instance of the "GraphicalApp" project. Doodle a bit so that you know the Immortal is up and running.
  3. Exit the GraphicalApp instance. Don't delete the log files.
  4. Start a new GraphicalApp instance. Use the same parameters from the first run.
  5. The GraphicalApp instance should go through recovery, replaying all the lines you drew previously, and then crash on the failed assert.

Example crash data

Below is a copy of the debug log from one of my failed runs up until the failed assert (with all DLL load messages removed). When the assert failed, the value of firstSeqNo was 250, and the value of curBuffer.LowestSeqNo was 260. Note that GraphicalApp runs the Immortal and the CRAWorker in the same process, so the debug log contains messages from both objects.

Starting CRA Worker instance [http://github.com/Microsoft/CRA]
   Instance Name: uwptestclientA0
   IP address: 10.106.188.94
   Port: 1500
   Secure network connections: Disabled
Exception thrown: 'System.Net.Sockets.SocketException' in System.dll
Disabling dynamic assembly loading
Ready ...
Logs directory: C:\franklinlogs\
*X* InstanceProxy created to communicate with . (Attach: False)
*X* Start Start()
*X* Received a checkpoint message
Exception thrown: 'System.Exception' in Ambrosia.exe
*X* Deserialized: GraphicalImmortalImpl.GraphicalImmortal
*X* End Start()
*X* Received an initial message
*X* InstanceProxy created to communicate with uwptestclientB. (Attach: True)
*X* Sending attach message to: uwptestclientB
Attaching to uwptestclientB
*X* Received a take checkpoint message
Reading a checkpoint 2286 bytes
*X* Sent checkpoint back to LAR
input  seq no: 249
input  replayable seq no: 0
SetFileValidData failed with error: Win32(1314) HRESULT(0X80070522)
SetFileValidData failed with error: Win32(1314) HRESULT(0X80070522)
restoring input:
restoring input:
restoring output:
restoring output:

I believe --rp and --sp on Ambrosia RegisterInstance should be renamed

After running these commands a million times, we take them for granted. But I ran into trouble trying to explain this in the documentation:

Ambrosia RegisterInstance -i myclient --rp 2000 --sp 2001 -l locallogs

Here's what they CLI help message says:

Usage: dotnet Ambrosia.dll RegisterInstance [OPTIONS]
Options:
  -i, --instanceName=VALUE   The instance name [REQUIRED].
      --rp, --receivePort=VALUE
                             The service receive from port [REQUIRED].
      --sp, --sendPort=VALUE The service send to port. [REQUIRED]

This phrasing is not clear -- "The service receive from port". What does that mean? From what and to what?

It seems that for RegisterInstance --rp/--sp are take the perspective of the coordinator.
Yet the user shouldn't really have to think about the ImmortalCoordinator, instead they think about their own application.

Then, if you call something like PerfTestInterruptible Client/Server the arguments are flipped, all of a sudden and --rp/--sp are reversed (same argument flags, but different meaning, or shifted to the perspective of the app).

It would be waaay better to call these --toCoord/--tc and --fromCoord/--fc, which does not leave room for confusion. Of course, when building a client for the wire protocol one has to know which port connects and which port accepts (sender connects convention for each direction of traffic).

System.Exception: 'Illegal leading byte in message: 51'

Somehow my client is getting out of sync on the stream with the ImmortalCoordinator.

In debugging I find this code in Importal.cs:

int commitID = this._ambrosiaReceiveFromStream.ReadIntFixed();
bytesToRead = this._ambrosiaReceiveFromStream.ReadIntFixed();
long checkBytes = this._ambrosiaReceiveFromStream.ReadLongFixed();
long writeSeqID = this._ambrosiaReceiveFromStream.ReadLongFixed();

matches this code in ImmortalCoordinator.Committer.Commit:

_workStream.Write(buf, 0, length);

When I check the stream they are both using the same socket (inverse) port numbers for LocalPort and RemotePort so I'm sure this is the same socket, and when I step over the _workStream.Write call the commitID arrives in my client app. But a weird thing then happens, the bytesToRead seems to skip ahead 4 bytes missing the actual bytesToRead and throwing the stream out of sync resulting in reaching the error case:

var s = String.Format("Illegal leading byte in message: {0}", firstByte);

I have no idea why this is happening, very reproducible. But just once today, it didn't happen and my client/server were working perfectly. Also this is all running on localhost, same box, so unlikely to be network weirdness. Also the HelloWorld app works perfectly every time. Any ideas?

Code Gen generated code that doesn't compile

The attached project results in ambrosia generated immortals that don't compile.

DistributedPropertyBag.zip

2>ImmortalSerializer.cs(14,7,14,36): warning CS0105: The using directive for 'PropertyBagImmortalInterfaces' appeared previously in this namespace
2>Proxy_IPropertyBagServerImmortal.cs(673,8,673,11): warning CS0219: The variable 'p_1' is assigned but its value is never used
...

Dynamic Port allocation

CRA already provides CRA.ClientLibrary.NetworkUtils.GetAvailablePort(), so can the ImmortalCoordinator use that instead of requiring user to come up with valid port numbers?

Bug in ElasticCircularBuffer

Hi Ambrosia team,

I am recently studying the Ambrosia source code. I think I may find a bug in ElasticCircularBuffer implemented in Ambrosia/Ambrosia/CircularBuffers.cs, though it seems not causing any trouble for now.

IEnumerable<T> Iterate()
{
    foreach (CircularBuffer<T> buffer in buffers)
    {
        foreach (T item in buffer.Iterate())
        {
             yield return item;
        }
    }
}

The first foreach iterates from buffers.First to buffers.Last. But this is actually not the desired behavior. Because when enqueued, the ElasticCircularBuffer reuses buffers.First if buffers.First contains an empty CircularBuffer, making buffers.First not actually the head. I also didn't see buffers.First being updated anywhere.

I guess it didn't cause any trouble because in testcases, CircularBuffer is big enough to hold all pending messages, so that ElasticCircularBuffer always contains only one CircularBuffer.

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.