hasura / graphql-engine

Blazing fast, instant realtime GraphQL APIs on your DB with fine grained access control, also trigger webhooks on database events.
https://hasura.io
Apache License 2.0
31.14k stars 2.77k forks source link

Actions don't work on Cloud Functions #3998

Closed andyfangaf closed 4 years ago

andyfangaf commented 4 years ago

Trying to have a custom mutation run on my Cloud Function which is served locally on http://localhost:5000/xxxx-52a3e/us-central1/auth-signUp

However, for some reason (I suspect because it's being called via http, not https), I am getting this error:

{
  "errors": [
    {
      "extensions": {
        "internal": {
          "type": "http_exception",
          "message": "ConnectionFailure Network.Socket.connect: <socket: 36>: does not exist (Connection refused)"
        },
        "path": "$",
        "code": "unexpected"
      },
      "message": "http exception when calling webhook"
    }
  ]
}

For reference here is the sample function:

import { https } from 'firebase-functions'

const signUp = https.onRequest((req, res) => {
  console.log(req, res)
})

export { signUp }
wwwdepot commented 4 years ago

You are calling auth-signUp which is undefined. You should be calling http://localhost:5000/xxxx-52a3e/us-central1/signUp

andyfangaf commented 4 years ago

It is auth-signUp because in my index file I have exported it as so:

import admin from 'firebase-admin'
import * as auth from './auth'

admin.initializeApp({
  projectId: 'xxxx-52a3e',
})

export { auth }

Sorry for not posting this earlier.

wwwdepot commented 4 years ago

localhost is resolved back to the container, not your host. That's why you see the connection error. So try to run the function on a live server.

andyfangaf commented 4 years ago

Is there an easier way for development? Or is the only way to deploy the function?

wwwdepot commented 4 years ago

You could use firebase serve -o YOUR_LAN_IP. See this if you want docker to access outside container.

andyfangaf commented 4 years ago

Hmm I think you're getting warmer on that @wwwdepot

I have this docker-compose.yml

version: '3.6'
services:
  postgres:
    image: postgres:12
    restart: always
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgrespassword
  graphql-engine:
    image: hasura/graphql-engine:v1.2.0-beta.1
    ports:
      - '8080:8080'
    depends_on:
      - 'postgres'
    restart: always
    environment:
      HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:postgrespassword@host.docker.internal:5432/postgres
      HASURA_GRAPHQL_ENABLE_CONSOLE: 'true'
      HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
      HASURA_GRAPHQL_ADMIN_SECRET: devpass
  node:
    image: node:10.19.0-alpine3.11
    ports:
      - '5000:5000'
volumes:
  db_data:

as you can see, the network mode is set to host and I'm connecting to postgres on host.docker.internal.

Problem is, I'm getting this error when running docker-compose up:

graphql-engine_1  | {"type":"startup","timestamp":"2020-03-03T02:28:19.157+0000","level":"info","detail":{"kind":"server_configuration","info":{"live_query_options":{"batch_size":100,"refetch_delay":1},"transaction_isolation":"ISOLATION LEVEL READ COMMITTED","plan_cache_options":{"plan_cache_size":null},"enabled_log_types":["http-log","websocket-log","startup","webhook-log","query-log"],"server_host":"HostAny","enable_allowlist":false,"log_level":"info","auth_hook_mode":null,"use_prepared_statements":true,"unauth_role":null,"stringify_numeric_types":false,"enabled_apis":["metadata","graphql","config","pgdump"],"enable_telemetry":true,"enable_console":true,"auth_hook":null,"jwt_secret":null,"cors_config":{"allowed_origins":"*","disabled":false,"ws_read_cookie":null},"console_assets_dir":null,"admin_secret_set":true,"port":8080}}}
graphql-engine_1  | {"type":"startup","timestamp":"2020-03-03T02:28:19.157+0000","level":"info","detail":{"kind":"postgres_connection","info":{"retries":1,"database_url":"postgres://postgres:...@host.docker.internal:5432/postgres"}}}
graphql-engine_1  | {"internal":"could not connect to server: Connection refused\n\tIs the server running on host \"host.docker.internal\" (192.168.65.2) and accepting\n\tTCP/IP connections on port 5432?\n","path":"$","error":"connection error","code":"postgres-error"}
xxx_graphql-engine_1 exited with code 1
graphql-engine_1  | {"type":"startup","timestamp":"2020-03-03T02:29:10.843+0000","level":"info","detail":{"kind":"server_configuration","info":{"live_query_options":{"batch_size":100,"refetch_delay":1},"transaction_isolation":"ISOLATION LEVEL READ COMMITTED","plan_cache_options":{"plan_cache_size":null},"enabled_log_types":["http-log","websocket-log","startup","webhook-log","query-log"],"server_host":"HostAny","enable_allowlist":false,"log_level":"info","auth_hook_mode":null,"use_prepared_statements":true,"unauth_role":null,"stringify_numeric_types":false,"enabled_apis":["metadata","graphql","config","pgdump"],"enable_telemetry":true,"enable_console":true,"auth_hook":null,"jwt_secret":null,"cors_config":{"allowed_origins":"*","disabled":false,"ws_read_cookie":null},"console_assets_dir":null,"admin_secret_set":true,"port":8080}}}
graphql-engine_1  | {"type":"startup","timestamp":"2020-03-03T02:29:10.843+0000","level":"info","detail":{"kind":"postgres_connection","info":{"retries":1,"database_url":"postgres://postgres:...@host.docker.internal:5432/postgres"}}}
graphql-engine_1  | {"internal":"could not connect to server: Connection refused\n\tIs the server running on host \"host.docker.internal\" (192.168.65.2) and accepting\n\tTCP/IP connections on port 5432?\n","path":"$","error":"connection error","code":"postgres-error"}
xxx_graphql-engine_1 exited with code 1

Do you know if there's something I'm missing?

wwwdepot commented 4 years ago

You don't need to change the docker-compose.yml file.

If you are on Docker for Mac/Windows 18.03+, change the action URL to http://host.docker.internal:5000/xxxx-52a3e/us-central1/auth-signUp.

Or, serve up your cloud function with command firebase serve --host 0.0.0.0, so hasura can access it via http://172.17.0.1:5000/xxxx-52a3e/us-central1/auth-signUp. 172.17.0.1 is the docker0's IP

marionschleifer commented 4 years ago

@fandy I'm closing this issue as the problem seems solved. Please feel free to re-open if you have any more questions 🙂

andyfangaf commented 4 years ago

Sorry @wwwdepot , but I'm going to re-open this again. using Zeit Now functions, I have this endpoint: http://localhost:3000/account/create, which returns a valid JSON response.

But when I use the Hasura action which calls http://docker.host.internal:3000/account/create, I get

{
  "errors": [
    {
      "extensions": {
        "internal": {
          "type": "http_exception",
          "message": "ConnectionFailure Network.Socket.getAddrInfo (called with preferred socket type/protocol: AddrInfo {addrFlags = [AI_ADDRCONFIG], addrFamily = AF_UNSPEC, addrSocketType = Stream, addrProtocol = 0, addrAddress = <assumed to be undefined>, addrCanonName = <assumed to be undefined>}, host name: Just \"docker.host.internal\", service name: Just \"3000\"): does not exist (Name or service not known)"
        },
        "path": "$",
        "code": "unexpected"
      },
      "message": "http exception when calling webhook"
    }
  ]
}

For reference, here's my docker-compose:

version: '3.6'

services:
  postgres:
    image: postgres:12
    restart: always
    volumes:
      - db_data:/var/lib/postgresql/data
    env_file:
      - .env

  graphql-engine:
    image: hasura/graphql-engine:v1.2.0-beta.2
    ports:
      - '8080:8080'
    depends_on:
      - 'postgres'
    restart: always
    env_file:
      - .env

  app:
    build: .
    ports:
      - '3000:3000'
    env_file:
      - .env

volumes:
  db_data:
wwwdepot commented 4 years ago

@fandy I think you are using the same port for docker-compose's app and local dev for zeit function.

  1. Use other port for zeit function or
  2. map the docker-compose app's port number to something else, e.g: 15000:3000
andyfangaf commented 4 years ago

@wwwdepot I've tried mapping the port to 4000, but get the same error. I think this is because Zeit functions is a part of Next.js all run on the same port anyways.

{
  "errors": [
    {
      "extensions": {
        "internal": {
          "type": "http_exception",
          "message": "ConnectionFailure Network.Socket.getAddrInfo (called with preferred socket type/protocol: AddrInfo {addrFlags = [AI_ADDRCONFIG], addrFamily = AF_UNSPEC, addrSocketType = Stream, addrProtocol = 0, addrAddress = <assumed to be undefined>, addrCanonName = <assumed to be undefined>}, host name: Just \"docker.host.internal\", service name: Just \"4000\"): does not exist (Name or service not known)"
        },
        "path": "$",
        "code": "unexpected"
      },
      "message": "http exception when calling webhook"
    }
  ]
}

Seems like it can't find the service on the same port that works but on docker.host.internal, which si confusing.

wwwdepot commented 4 years ago

Sorry didn't ask for your dev environment at first. I was assuming your next.js app running on your local machine, hasura & postgres running inside docker.

docker.host.internal gives you access to docker host's local network.

If your next.js is the app service in the docker-compose file, hasura access it using http://app:3000/blah_blah_blah. Docker can resolve it automatically within its network by service name within the same network.

Can you deploy the function to glitch.com, and test the hasura's action is working fine with a connection to a live URL. Just to make sure there's no problem with hasura rather a network-config problem with docker.

andyfangaf commented 4 years ago

http://service-name:3000/account/create works for development! Thank you.

followbl commented 4 years ago

@wwwdepot any recommendations on where to point it the app is running outside of docker. We basically have the exact same setup as @fandy but we're running the build outside of docker - everything works as expected with the exception of hasura actions 😿

followbl commented 4 years ago

for anyone stumbling up on this issue - our issue is the same as above but for deeper context, existed in github-actions where we're treating it as a CI with a fresh hasura instance being spun up and migrated via docker-compose and a locally built/compiled nextjs application running locally on localhost:3000 (this is so we can run a full integration test (cypress) against it)...only hasura actions wouldn't work because as of right now linux docker does not understand host.docker.internal...

The fix is a bit of a hack but works until a PR for linux docker and docker-compose to treat host.docker.internal the same as it does on mac and windows.

we ran ifconfig on the ci to get the address docker is running on and added it to extra hosts - like so

  graphql-engine:
    image: hasura/graphql-engine:v1.3.0-beta.4
    ports:
      - '8080:8080'
    extra_hosts:
      - host.docker.internal:172.17.0.1
    depends_on:
      - 'postgres-server'
    restart: always
    environment:
wwwdepot commented 4 years ago

@followbl If your container cannot resolve external networks, try add the DNS to the docker-compose file

  graphql-engine:
    image: hasura/graphql-engine:v1.3.0-beta.4
    ports:
      - '8080:8080'
    extra_hosts:
      - host.docker.internal:172.17.0.1
    depends_on:
      - 'postgres-server'
    restart: always
    dns:
      - 1.1.1.1