Closed darting closed 9 months ago
Thank you for reporting, @darting. I'll try to address it soon
hi @ReubenBond , I added a new module for testing but seems got another exceptions.
the code as below: https://github.com/darting/orleans-fsharp/blob/master/src/Games/Adventure.fs
https://github.com/darting/orleans-fsharp/blob/master/src/Client/Program.fs#L67
the exception error:
Unhandled Exception: System.AggregateException: One or more errors occurred. (Named type "Games.Games.Games.Adventure.PlayerStore.State" is invalid: Type string "Games.Games.Games.Adventure.PlayerStore.State" cannot be resolved.) ---> System.TypeAccessException: Named type "Games.Games.Games.Adventure.PlayerStore.State" is invalid: Type string "Games.Games.Games.Adventure.PlayerStore.State" cannot be resolved.
at Orleans.Serialization.BinaryTokenStreamReaderExtensinons.ReadSpecifiedTypeHeader(IBinaryTokenStreamReader this, SerializationManager serializationManager)
at Orleans.Serialization.BinaryTokenStreamReaderExtensinons.ReadFullTypeHeader(IBinaryTokenStreamReader this, SerializationManager serializationManager, Type expected)
at Orleans.Serialization.BinaryTokenStreamReaderExtensinons.ReadSpecifiedTypeHeader(IBinaryTokenStreamReader this, SerializationManager serializationManager)
at Orleans.Serialization.SerializationManager.DeserializeInner(Type expected, IDeserializationContext context)
at Orleans.Serialization.BuiltInTypes.DeserializeOrleansResponse(Type expected, IDeserializationContext context)
at Orleans.Serialization.SerializationManager.DeserializeInner(Type expected, IDeserializationContext context)
at Orleans.Serialization.SerializationManager.Deserialize(Type t, IBinaryTokenStreamReader stream)
at Orleans.Runtime.Message.GetDeserializedBody(SerializationManager serializationManager)
at Orleans.Runtime.GrainReferenceRuntime.ResponseCallback(Message message, TaskCompletionSource`1 context)
--- 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 Orleans.OrleansTaskExtentions.<<ToTypedTask>g__ConvertAsync4_0>d`1.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 System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at Program.worker4@80-2.Invoke(Unit unitVar0) in /orleans-fsharp/src/Client/Program.fs:line 80
to run the client project should enable this line: https://github.com/darting/orleans-fsharp/blob/master/src/Client/Program.fs#L113
Thanks
@darting add the new module to application parts
hi @ReubenBond , hmm why? for other modules I never add to application parts.
And I found that the error message telling (Named type "Games.Games.Games.Adventure.PlayerStore.State" is invalid: Type string "Games.Games.Games.Adventure.PlayerStore.State" cannot be resolved.)
.
But actually my type should be Games.Adventure.PlayerStore.State
https://github.com/darting/orleans-fsharp/blob/master/src/Games/Adventure.fs#L32
I'm taking a look at this today. I couldn't get your example to build/run, but I tried testing this class and it worked for me:
public interface IGame<TState, TAction> : IGrainWithStringKey
{
Task<TState> Go(TAction act);
}
public class GameGrain<TState, TAction> : Orleans.Grain, IGame<TState, TAction>
{
public Task<TState> Go(TAction act) => Task.FromResult(default(TState));
}
// Then I call the Go method in a startup task.
@ReubenBond Hi, I was test on my Macbook, I will try to make a clear project. Will update here later.
Hi @ReubenBond , I had create two branch for two cases; https://github.com/darting/orleans-fsharp/tree/testcase-1 https://github.com/darting/orleans-fsharp/tree/testcase-2
they got diff exceptions, the only difference between them is here: https://github.com/darting/orleans-fsharp/blob/testcase-1/src/Grains/Library.fs#L19 https://github.com/darting/orleans-fsharp/blob/testcase-2/src/Grains/Library.fs#L19
Hopefully they are clear.
Thanks
PS: already update to orleans 2.0-rc1
hi, @ReubenBond, Had you try like this in C#?
public interface IGame<TState, TAction> : IGrainWithStringKey
{
Task<TState> Go(TState prevState, TAction act);
}
public interface IReducer<TState, TAction> {
Task<TState> Handle(TState prevState, TAction act);
}
public class Reducer1 : IReducer<String, Reducer1Action> {
// todo
}
public class Reducer2 : IReducer<Int32, Reducer2Action> {
// todo
}
public class GameGrain<TState, TAction> : Orleans.Grain, IGame<TState, TAction>
{
IReducer<TState, TAction> _reducer;
public GameGrain(IReducer<TState, TAction> reducer) {
_reducer = reducer;
}
public Task<TState> Go(TState prevState, TAction act) => _reducer.Handle(prevState, act);
}
And inject these two reducers to serviceCollection:
services.AddSingleton<IReducer<String, Reducer1Action>>(x => new Reducer1());
services.AddSingleton<IReducer<Int32, Reducer2Action>>(x => new Reducer2());
Call from Client:
var game1 = client.GetGrain<IGame<String, Reducer1Action>> ("reducer1");
var game2 = client.GetGrain<IGame<Int32, Reducer2Action>> ("reducer2");
Sorry it is too late here, I will try it myself tmw. Thanks.
Oh, I understand, so the issue isn't with generic grains themselves, but with their generic parameters being used in constructor arguments. Thanks for the clarification, I'll take another look
@darting am I doing this wrong? This is working for me:
[Fact]
public async Task CanUseGenericArgumentsInConstructor()
{
var grain = this.fixture.GrainFactory.GetGrain<IReducerGameGrain<string, Reducer1Action>>("reducer1");
Assert.NotNull(await grain.Go("378", new Reducer1Action()));
var grain2 = this.fixture.GrainFactory.GetGrain<IReducerGameGrain<int, Reducer2Action>>("reducer2");
Assert.NotEqual(0, await grain2.Go(378, new Reducer2Action()));
}
[Serializable]
public class Reducer1Action { }
[Serializable]
public class Reducer2Action { }
public class Reducer1 : IReducer<string, Reducer1Action>
{
public Task<string> Handle(string prevState, Reducer1Action act) => Task.FromResult(prevState + act);
}
public class Reducer2 : IReducer<Int32, Reducer2Action>
{
public Task<int> Handle(int prevState, Reducer2Action act) => Task.FromResult(prevState + act.ToString().Length);
}
public interface IReducerGameGrain<TState, TAction> : IGrainWithStringKey
{
Task<TState> Go(TState prevState, TAction act);
}
public class ReducerGameGrain<TState, TAction> : Grain, IReducerGameGrain<TState, TAction>
{
private readonly IReducer<TState, TAction> reducer;
public ReducerGameGrain(IReducer<TState, TAction> reducer)
{
this.reducer = reducer;
}
public Task<TState> Go(TState prevState, TAction act) => this.reducer.Handle(prevState, act);
}
hi @ReubenBond, I think in C# it is work well but F# doesn't work.
case 1, generic parameters being used in constructor arguments
not working. example:
type GameGrain<'State, 'Action> (reducer: IReducer<'State, 'Action>) =
inherit Grain ()
interface IGame<'State, 'Action> with
member __.Go prev act = reducer.Handle prev act
case 2, if the 'State
is a tuple, example type State = String * Int32
, the Client side will receive a wrong type info. But if I change to type State = State of String * Int32
it is work
you can take a look this branch: https://github.com/darting/orleans-fsharp/tree/testcase-3
> cd src/Host
> dotnet run
> cd src/Client
> dotnet run
Thanks for the sample. I'm debugging it now. It appears to be an issue with how nested generic types are formatted
As a workaround until we can rectify this, @darting, you can use a namespace instead of a module so that GameGrain
isn't encoded as a nested type.
Wow , thanks.. use a namespace it is working
hi @sergeybykov , is that means for v2 orleans will not fix the nested generic types issue on F#? since my project is pure f# just wondering if will encounter other issue?
Thanks
@ReubenBond
I think I found another issue. Lets say:
I have an interface:
type IGame<'GameState, 'GameAction> =
abstract Reducer : 'GameState -> 'GameAction -> Task<'GameState>
And I have a grain :
type GameGrain<'State, 'Action> (store : IGameStore<'State, 'Action>) =
interface IGameActor<'State, 'Action> with
member this.Reducer prev act = Task.FromResult prev
It is not work !!!
The diff is the generics type name is diff. In the interface I used 'GameState
but for grain I used 'State
It will tell me that
Cannot find an implementation class for grain interface, Make sure the grain assembly was correctly deployed and loaded in the silo.
type IGame<'GameState, 'GameAction> = abstract Reducer : 'GameState -> 'GameAction -> Task<'GameState>
@darting All my Orleans code is in F# so I ran into this early on. In F# we can get away with making interfaces with un-tupled arguments, but Orleans doesn't understand these. Also, give your parameters names.
type IGame<'GameState, 'GameAction> =
inherit IGrainWithSomeSortaKey
abstract Reducer : state:'GameState * action:'GameAction -> Task<'GameState>
Give that a try.
I believe this is fixed now (in v7.2.4+). If not, please open a new issue and reference this one.
Hi there, is there any way to support generic type on an Grain? e.g.
** https://github.com/darting/orleans-fsharp/blob/master/src/Grains/Library.fs#L19-L27
If I try to get a grain uses:
** https://github.com/darting/orleans-fsharp/blob/master/src/Client/Program.fs#L21 Orleans will throw exception
here is my test repo https://github.com/darting/orleans-fsharp/blob/master/src/Client/Program.fs#L19 https://github.com/darting/orleans-fsharp/blob/master/src/Grains/Library.fs#L19 https://github.com/darting/orleans-fsharp/blob/master/src/Host/Program.fs#L12
Thanks