Comments (26)
Thanks for your reply.
Let me try to explain you steps.
My server is running as per the documentation in this repository.
Serverless: Offline [HTTP] listening on http://localhost:3000
Serverless: Offline [websocket] listening on ws://localhost:3001
My serverless.yml looks like
functions:
httpHandler:
handler: graphql.handleHTTP
events:
- http:
path: /
method: any
cors: true
wsHandler:
handler: graphql.handleWebSocket
events:
- websocket:
route: $connect
- websocket:
route: $disconnect
- websocket:
route: $default
eventProcessorHandler:
handler: graphql.handleEvents
events:
- stream:
enabled: true
type: dynamodb
arn:
Fn::GetAtt: [EventsDynamoDBTable, StreamArn]
If i open GraphQL playground at http://localhost:3000
, I can successfully speak with the server and do queries and mutations. In my mutation I am also publishing and I can verify this in the DynamoDB Events
table which class DynamoDBEventStore
uses.
export const createSomething = async (
_: any,
{ foo, bar }: FooBar,
{
dataSources,
pubsub
}: { dataSources: { baz: BazApi }; pubsub: PubSub }
) => {
const response = await dataSources.baz.createSomething(
foo as Foo,
bar as Bar
);
await pubsub.publish(SOMETHING_CREATED, response);
return response;
};
The problem is if i open GraphQL Playground in two browsers, Run subscription in one browser so that it goes to listening... mode and run mutation in the other browser.
My expectation is that the Connections
, Subscriptions
and SubscriptionOperations
table in Dynamodb should be populated by this time with a record based on one client is on listening mode.
However, that listening mode stays as it is forever. However, I see one record populated in the Events
table.
Please let me know if you have more questions. I know I am not able to put properly into words the problem.
from aws-lambda-graphql.
Thanks for your reply.
I was trying to dig in the code and found two things that I need to do.
1 - In order to use GraphQL playground that comes with ApolloServer, we need to tell the websocket URL explicitly
const server = new Server({
connectionManager,
eventProcessor: new DynamoDBEventProcessor(),
resolvers,
subscriptionManager,
typeDefs,
dataSources,
context: {
pubsub
},
playground: {
subscriptionEndpoint: "ws://localhost:3001"
}
});
After doing this, If i run subscription via PlayGround, it connects fine.
2 - Second in file DynamoDBConnectionManager.js
the this.hydrateConnection
method was failing because it was trying to read record from Connections
table and returning empty {}. I think its a race condition somehow. I explicitly set the retryCount
variable to 5
and it worked until here.
Now my situation is that I can subscribe to the server, my PlayGround is in listening mode, The records are created in Connections
, Subscriptions
, SubscriptionOperations
table which seems all good. However, upon mutation, my subscription client is still on listening mode. If I check Events
table, there is a published event present which I published in my mutation function.
Can you see what could potentially be wrong here.?
Thanks alot for helping.
from aws-lambda-graphql.
I don't have any experience with localstack but you already know that your stream is not listening to events from dynamodb because that is something that is handled by https://github.com/michalkvasnicak/aws-lambda-graphql/blob/master/packages/chat-example-server/serverless.yml#L11
So you need to find a way how to listen to those changes and call the event handler for event processor. That's not something that is a part of this library because in AWS DynamoDB Stream is responsible for calling your Lambda function. In local environment you need an intermediary mechanism that will connect to a stream and call your handler.
from aws-lambda-graphql.
@IslamWahid I added the code you proposed to the server example.
from aws-lambda-graphql.
@raheelkhan could please provide how you test it.
- you use playground to connect to this endpoint and listen to subscription (if listening mode runs then this part is ok)
- do you fire some action using Mutation to publish events?
I don't understand what effect should be visible on server. Could you please explain it?
from aws-lambda-graphql.
@raheelkhan thank you, could you please provide a schema definition and how the context and pubSub are created?
from aws-lambda-graphql.
Sure,
Main
const eventStore = new DynamoDBEventStore({ dynamoDbClient });
const pubsub = new PubSub({ eventStore });
const subscriptionManager = new DynamoDBSubscriptionManager({ dynamoDbClient });
const connectionManager = new DynamoDBConnectionManager({
apiGatewayManager: process.env.IS_OFFLINE
? new ApiGatewayManagementApi({ endpoint: "http://localhost:3001" })
: undefined,
dynamoDbClient,
subscriptions: subscriptionManager
});
const server = new Server({
connectionManager,
eventProcessor: new DynamoDBEventProcessor(),
resolvers,
subscriptionManager,
typeDefs,
dataSources,
context: {
pubsub
}
});
export const handleWebSocket = server.createWebSocketHandler();
export const handleHTTP = server.createHttpHandler();
export const handleEvents = server.createEventHandler();
Schema
type WalkinAppointment {
contactId: Int!
productId: Int!
appointmentId: Int!
}
type Subscription {
somethingCreated: Something!
}
Subscription Resolver
const dynamoDbClient = new DynamoDB.DocumentClient({
endpoint: process.env.ENDPOINT_DYNAMODB
});
const eventStore = new DynamoDBEventStore({ dynamoDbClient });
const pubsub = new PubSub({ eventStore });
export const resolvers: IResolvers = {
Query: {
...
},
Mutation: {
createSomething
},
Subscription: {
walkinAppointmentCreated: {
subscribe: () => pubsub.subscribe(SOME_THING_CREATED)
}
}
};
from aws-lambda-graphql.
My Mutation part is working fine, the pubsub.publish()
in the mutation function createSomething
is also working as expected. Only I am not able to use the websocket feature.
upon start of server it says websocket server is running on ws://localhost:3001
. I tried from developers tools var websocket = new WebSocket("ws://localhost:3001");
and it is connected successfully. Which means the API Gateway part is running fine.
from aws-lambda-graphql.
I'm sorry for the late response. Could you please change the subscribe: () => pubsub.subscribe(SOME_THING_CREATED)
to subscribe: pubSub.subscribe(SOME_THING_CREATED)
?
The problem is that subscribe
has same notation as resolver
so when the subscribe
is called, it gets root, args, context, info
arguments. pubSub.subscribe()
returns a function with the same notation so you have 2 ways how to do it:
export const resolvers: IResolvers = {
Query: {
/* ... */
},
Mutation: {
/* ... */
},
Subscription: {
walkinAppointmentCreated: {
subscribe: pubsub.subscribe(SOME_THING_CREATED)
}
}
};
or
export const resolvers: IResolvers = {
Query: {
/* ... */
},
Mutation: {
/* ... */
},
Subscription: {
walkinAppointmentCreated: {
subscribe: (...args) => pubsub.subscribe(SOME_THING_CREATED)(...args)
}
}
};
If you need to access pubSub
from the context, please follow https://github.com/michalkvasnicak/aws-lambda-graphql#16-pass-pubsub-to-resolvers-using-graphql-context
from aws-lambda-graphql.
Only thing that comes to my mind is that setting up subscriptions
using pubSub.subscribe()
is fragile. It's really easy to mess it up as I explained in the comment above.
Basically you have to define subscribe
in your schema correctly.
{
subscribe: pubSub.subscribe(event);
}
or
{
subscribe: (...args) => pubSub.subscribe(event)(...args);
}
or with context
{
subscribe: (root, args, ctx, info) => ctx.pubSub.subscribe(event)(root, args, ctx, info);
}
If you have your subscriptions set up like this, then there shouldn't be a problem.
Other thing could be some problem with serverless-offline
.
What version of aws-lambda-graphql
are you using? Race condition should be fixed in #68 which was released as 1.0.0-alpha.3
from aws-lambda-graphql.
for race condition in my observation hydrateConnection
retries only once. Is there any way we can pass this as an argument?
from aws-lambda-graphql.
I don't understand how it can result in a race condition.
- When you connect to WebSocket using subscription the
$connect
route is called and the connection is registered. - Then you fire mutation right? So it's published after the connection is established.
I assume that you test it manually, that means that you should be able to prevent any weird cases. If it doesn't work even when you first subscribe and then fire a mutation after few seconds then it's really weird.
Basically you have a problem when you want to publish event back to subscribers (because you have an event in Events table).
Only thing I have from you is the code in comment:
const dynamoDbClient = new DynamoDB.DocumentClient({
endpoint: process.env.ENDPOINT_DYNAMODB
});
const eventStore = new DynamoDBEventStore({ dynamoDbClient });
const pubsub = new PubSub({ eventStore });
export const resolvers: IResolvers = {
Query: {
...
},
Mutation: {
createSomething
},
Subscription: {
walkinAppointmentCreated: {
subscribe: () => pubsub.subscribe(SOME_THING_CREATED)
}
}
};
Given this code, it's not correct because walkinAppointmentCreated
should be defined like this:
const dynamoDbClient = new DynamoDB.DocumentClient({
endpoint: process.env.ENDPOINT_DYNAMODB
});
const eventStore = new DynamoDBEventStore({ dynamoDbClient });
const pubsub = new PubSub({ eventStore });
export const resolvers: IResolvers = {
Query: {
...
},
Mutation: {
createSomething
},
Subscription: {
walkinAppointmentCreated: {
subscribe: (...args) => pubsub.subscribe(SOME_THING_CREATED)(...args)
}
}
};
from aws-lambda-graphql.
Sorry, I forgot to mention I am already using the same way you have mentioned. Problem lies somewhere in DynamoDBEventProcessor class. My subscriptions are registered. Only I am not receiving response from server it keeps on listening mode. I am trying to find loophole. I will update you.
Thanks
from aws-lambda-graphql.
@raheelkhan have you tried to change retry count in code of library if it helps?
from aws-lambda-graphql.
@michalkvasnicak Yes this is one part of the issue.
In file DynamoDBConnectionManager.js:19
I have set up hard value 5
in the for
loop instead of retryCount
. This solves my first problem where my subscription are being registered.
from aws-lambda-graphql.
The second problem is that it does not send a data over subscription back to client that has subscribed? This one is weird because the connection already should exist in your table, so there shouldn't be any problem with fetching the connection.
Does event processor even receive events from DynamoDB event stream?
from aws-lambda-graphql.
Does event processor even receive events from DynamoDB event stream?
Can you please guide me how can I track that, this is what I am struggling to reach.
from aws-lambda-graphql.
Basically this is the code of event processor:
It should be enough just to check what Records
contain. https://github.com/michalkvasnicak/aws-lambda-graphql/blob/master/packages/aws-lambda-graphql/src/DynamoDBEventProcessor.ts#L33
If event processor is being called then you should be able to see events received from DynamoDB.
from aws-lambda-graphql.
If is logged then you can pass eventProcessor
with onError
handler and log errors that occurred during event processing.
const server = new Server({
/* ... */
eventProcessor: new DynamoDBEventProcessor({ onError: e => console.log(e) }),
});
from aws-lambda-graphql.
I think eventProcessor is not getting called in my case. Its only working for httpHandler
I put this line in the DynamoDBEventProcessor::createHandler(server)
.
const connectionManager = new DynamoDBConnectionManager({
apiGatewayManager: process.env.IS_OFFLINE
? new ApiGatewayManagementApi({ endpoint: "http://localhost:3001" })
: undefined,
dynamoDbClient,
subscriptions: subscriptionManager
});
is the apiGatewayManager
url matters in this situtation ? I am not using this url anywhere, just followed it from the documentation of this package.
from aws-lambda-graphql.
Ok, that can be maybe some problem with your serverless.yml configuration. Did you compare it with https://github.com/michalkvasnicak/aws-lambda-graphql/blob/master/packages/chat-example-server/serverless.yml?
from aws-lambda-graphql.
I compared, I am not using serverless-dynamodb-local, instead I am using localstack which has dynamodb builtin. But other things are same.
from aws-lambda-graphql.
@raheelkhan have you found a solution? It could be nice to have a mention about how to use this with a local stack in README and maybe an example for local stack :)
from aws-lambda-graphql.
from aws-lambda-graphql.
Ok thank you very much, I'm closing this for now. If anyone stumbles on this issue and has a solution for LocalStack, feel free to post here.
from aws-lambda-graphql.
playground: {
subscriptionEndpoint: "ws://localhost:3001"
}
@michalkvasnicak Can you please update that on the server example?
from aws-lambda-graphql.
Related Issues (20)
- 502 bad gateway using type-graphql HOT 1
- Usage w/ Apollo Federation HOT 1
- Client not receiving updates HOT 1
- Expose unsubscribe in PubSub HOT 1
- Scaling related questions HOT 1
- Do I must to use DynamoDB storage? HOT 1
- How do I listen on the socket of 'connect' 'disconnet' method ? HOT 1
- Send the events from other apis HOT 2
- Duplicated message every period of time
- Error "Address already in use" while running example chat server with serverless-offline
- Routes for webSocketHandler, dynamoDBStreamHandler and httpHandler not create
- AWS SDK v3 Compatibility HOT 2
- The packages demo can't running
- How to pass DataSources to Context? HOT 2
- How to use at aws?
- How can I access express object from context function?
- How to use subscriptions with `type-graphql`? HOT 1
- InvalidSignatureException Error after moving from Regional Gateway to CloudFront
- Any plans for support apollo server 3? HOT 3
- Deleting old subscribers fails with ValidationException
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from aws-lambda-graphql.