-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace GraphQL subscriptions by queries + polling #203
Conversation
The Graph is having issues with GraphQL subscriptions, so we are moving to queries with polling for the time being. Once subscriptions get enabled again on The Graph, we will move back to GraphQL subscriptions.
Codecov Report
@@ Coverage Diff @@
## master #203 +/- ##
==========================================
+ Coverage 34.96% 35.88% +0.91%
==========================================
Files 98 99 +1
Lines 1799 1856 +57
Branches 276 304 +28
==========================================
+ Hits 629 666 +37
- Misses 1170 1190 +20
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Such a simple change. :)
On a separate note: I'm guessing there are other examples out of date, right?
This is so app connectors don’t have to change it to `query`, then back to ${type} whenever we will support GraphQL subscriptions again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes look great, I left a comment on how we may want to generalize the GraphQLWrapper
POLL_INTERVAL
as a constructor argument so app connectors and even users doing custom queries may get more granularity on the interval, as discussed.
Two for now: - Parcel - Webpack with ts-loader
Also remove the unecessary passing of The Graph URLs.
Indeed! All the examples should be up to date now: #205 |
pollInterval is an option that can be set on all the TheGraph connectors. This commit also adds the possibility to consume the organization connector from any app connector, allowing to retrieve its options for example. This was done so that app connectors using TheGraph can inherit from pollInterval defined in the main connector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work, I leave a few considerations for a few of the types. I also notice that the Tokens app connector is a bit different of the rest. I wonder if after merging this one we might want to refactor it to keep a single way of implementing connectors.
Other than that everything looks good 🙌
@@ -28,16 +28,25 @@ export function subgraphUrlFromChainId(chainId: number) { | |||
return null | |||
} | |||
|
|||
type AgreementConnectorTheGraphConfig = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can generalize this type for every app connector? Then if the specific app connector wants can extent it to include extra configurations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean for our connectors only, or as a type that would be exported by connect-core
for any connector to extend the base config? The way I see it, a connector configuration is the responsibility of the connector defining it, even if they happen to be identical in our case because we follow the same conventions. What do you think?
packages/connect-core/src/connections/IOrganizationConnector.ts
Outdated
Show resolved
Hide resolved
@@ -1,27 +1,33 @@ | |||
import { createAppConnector, Network } from '@aragon/connect-core' | |||
import { IFinanceConnector } from './types' | |||
import { createAppConnector } from '@aragon/connect-core' | |||
import Finance from './models/Finance' | |||
import FinanceConnectorTheGraph, { | |||
subgraphUrlFromChainId, | |||
} from './thegraph/connector' | |||
|
|||
type Config = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I notice every app connector also defines this type. I wonder if it's ok to be redundant on those types or we should apply the DRY principle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess in our case we might want to have a base that we would extend, but I also like the idea of keeping them separate, even if it require some repetition, because it makes it easy for connector authors to take one and use it as a bootstrap. What do you think?
|
||
const token = await gql.performQueryWithParser<Token>( | ||
queries.TOKEN('query'), | ||
{ tokenManagerAddress: appAddress }, | ||
{ tokenManagerAddress: config.appAddress }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking through the other connectors we are handling the Tokens app connector a bit differently, using the create
method. I wonder if we might want to refactor it a bit to keep a single source of truth on how connectors are implemented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using create()
is needed in the tokens app connector, because it’s the only one that need to instantiate asynchronously. What would you think of moving all the connectors to an async create()
, even if they don’t need it (yet)?
This commit contains various improvements for the React API. ## Loading behavior Since we replaced the GraphQL subscriptions by queries with polling (see #203), the hooks provided by the React API were updating too often, and incorrectly (see #216). This version is now taking care of only triggering updates when a changed happened, and to only use loading states when necessary. ## createAppHook(): allow connector configuration to be set App connectors can receive a source connector and its options, but this wasn’t possible when using `createAppHook()`. A second parameter has been added, to either pass a specific connector or to change its options: import connectVoting from '@aragon/connect-voting' import { createAppHook } from '@aragon/connect-react' const useVoting = createAppHook(connectVoting, ['thegraph', { subgraphUrl: 'https://…' }]) ## createAppHook(): dependencies array Hooks created through `createAppHook()` now accept a dependency array, that can get used to refresh its callback. When no dependency array is passed, the callback never updates. import connect from '@aragon/connect' import connectVoting from '@aragon/connect-voting' import { createAppHook, useApp } from '@aragon/connect-react' const useVoting = createAppHook(connectVoting) function App() { const [page, setPage] = useState(0) const [voting] = useApp('voting') const [votes] = useVoting(voting, app => ( app.votes({ first: 10, skip: 10 * page }) ), [page]) return ( <div> <button onClick={() => setPage(page + 1)}>prev</button> <button onClick={() => setPage(page - 1)}>next</button> </div> ) } ## Populating status.error rather than throwing errors In many cases, errors were thrown rather than populating the `status.error` object in the React API. It is an issue that was also happening with the JS API (see #229). It has now been fixed. import connect from '@aragon/connect' import connectVoting from '@aragon/connect-voting' import { createAppHook, useApp } from '@aragon/connect-react' const useVoting = createAppHook(connectVoting) function App() { const [voting, votingStatus] = useApp('voting') const [votes, votesStatus] = useVoting(voting, app => app.votes()) if (votingStatus.error) { return ( <h1>Error: {votingStatus.error.message}</h1> ) } if (votesStatus.error) { return ( <h1>Error: {votesStatus.error.message}</h1> ) } return ( // … ) } ## App methods subscriptions Prior to this version, it was not possible to subscribe to app methods using `createAppHook()`. The fetched data was returned once, and only updated when the component was mounted again. The feature has been added, and we can now subscribe to any app methods, alongside the core ones (`useApp()`, `usePermissions()`, …). Every part of the React API is now listening to changes and reacting accordingly. To use this feature, the subscription methods (`onX`) should be called, but without passing a callback. `createAppHook()` will take care of handling the subscription. import connect from '@aragon/connect' import connectVoting from '@aragon/connect-voting' import { createAppHook, useApp } from '@aragon/connect-react' const useVoting = createAppHook(connectVoting) function App() { const [voting, votingStatus] = useApp('voting') // To enable a subscription, use app.onVotes() rather than app.votes(). // Note that the default value can be set using the assignment default. const [votes = [], votesStatus] = useVoting(voting, app => app.onVotes()) return ( // … ) } Of course, it also works with the dependencies array, taking care of unsubscribing and subscribing to the new query: import connect from '@aragon/connect' import connectVoting from '@aragon/connect-voting' import { createAppHook, useApp } from '@aragon/connect-react' const useVoting = createAppHook(connectVoting) function App() { const [page, setPage] = useState(0) const [voting] = useApp('voting') const [votes] = useVoting(voting, app => ( // Note the app.onVotes() rather than app.votes(). app.onVotes({ first: 10, skip: 10 * page }) // The subscription will refresh every time `page` changes. ), [page]) return ( // … ) } Important: this only works with app connectors enabling this syntax. All the core app connectors have been updated for it, but third party app connectors will require to be updated too.
The Graph is having issues with GraphQL subscriptions, so we are moving to queries with polling for the time being. Once subscriptions get enabled again on The Graph, we will move back to GraphQL subscriptions.
Also in this PR:
nodejs/
demos update.