Graphql-go: Data race on schema parsing

Created on 12 Apr 2018  路  6Comments  路  Source: graph-gophers/graphql-go

I've stumbled upon this in a service where schema is not parsed globally in a init func, but passed as a dependency to given resolver. Placing t.Parallel() before schema parsing causes data races found by the race detector. Placing it after the parsing solves the issue. Decided to try and reproduce it with the starwars example.

Example tests over github.com/graph-gophers/graphql-go/example/starwars with t.Parallel():

package starwars_test

import (
        "testing"

        graphql "github.com/graph-gophers/graphql-go"
        "github.com/graph-gophers/graphql-go/example/starwars"
)

func TestParse1(t *testing.T) {
        t.Parallel()
        graphql.ParseSchema(starwars.Schema, &starwars.Resolver{})
}

func TestParse2(t *testing.T) {
        t.Parallel()
        graphql.ParseSchema(starwars.Schema, &starwars.Resolver{})
}

When executed with the race detector:

==================
WARNING: DATA RACE
Read at 0x00c4200b8928 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xc5
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c4200b8928 by goroutine 7:
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:352 +0x131
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse2()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:17 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c420197660 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:63 +0x129
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xf0
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c420197660 by goroutine 7:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:67 +0x198
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xf0
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse2()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:17 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c4201976b0 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:57 +0x4f1
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xf0
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c4201976b0 by goroutine 7:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:61 +0x560
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xf0
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse2()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:17 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c4201976a0 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:63 +0x129
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:57 +0x518
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xf0
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c4201976a0 by goroutine 7:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:67 +0x198
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:57 +0x518
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xf0
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse2()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:17 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c4200d04f0 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/schema.resolveInputObject()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:382 +0xfc
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:356 +0x22b
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c4200d04f0 by goroutine 7:
  github.com/graph-gophers/graphql-go/internal/schema.resolveInputObject()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:386 +0x15b
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:356 +0x22b
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse2()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:17 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c4200b8c28 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xc5
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c4200b8c28 by goroutine 7:
  [failed to restore the stack]

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c4201970a0 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:63 +0x129
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xf0
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c4201970a0 by goroutine 7:
  [failed to restore the stack]

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c4201970e0 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:57 +0x4f1
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:63 +0x150
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xf0
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c4201970e0 by goroutine 7:
  [failed to restore the stack]

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c4201970d0 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:63 +0x129
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:57 +0x518
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:63 +0x150
  github.com/graph-gophers/graphql-go/internal/schema.resolveField()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:348 +0xf0
  github.com/graph-gophers/graphql-go/internal/schema.resolveNamedType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:329 +0x2f5
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:258 +0x211
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c4201970d0 by goroutine 7:
  [failed to restore the stack]

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c4200d0100 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:264 +0x3b5
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c4200d0100 by goroutine 7:
  [failed to restore the stack]

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
==================
WARNING: DATA RACE
Read at 0x00c420197b90 by goroutine 6:
  github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/common/types.go:63 +0x129
  github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/internal/schema/schema.go:264 +0x3e0
  github.com/graph-gophers/graphql-go.ParseSchema()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/graphql.go:37 +0x23a
  github.com/graph-gophers/graphql-go/example/starwars_test.TestParse1()
      /home/kiril/go/src/github.com/graph-gophers/graphql-go/example/starwars/starwars_test.go:12 +0xa9
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d

Previous write at 0x00c420197b90 by goroutine 7:
  [failed to restore the stack]

Goroutine 6 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/lib/go/src/testing/testing.go:824 +0x564
  testing.runTests.func1()
      /usr/lib/go/src/testing/testing.go:1063 +0xa4
  testing.tRunner()
      /usr/lib/go/src/testing/testing.go:777 +0x16d
  testing.runTests()
      /usr/lib/go/src/testing/testing.go:1061 +0x4e1
  testing.(*M).Run()
      /usr/lib/go/src/testing/testing.go:978 +0x2cd
  main.main()
      _testmain.go:46 +0x22a
==================
--- FAIL: TestParse2 (0.01s)
    testing.go:730: race detected during execution of test
--- FAIL: TestParse1 (0.01s)
    testing.go:730: race detected during execution of test
FAIL
FAIL    github.com/graph-gophers/graphql-go/example/starwars    0.020s

Most helpful comment

Looking at this problem again, I the root cause of the race is the sharing of Types and Directives between new schemas and the Meta schema. I suspect that copying Meta.Types and Meta.Directives in schema.New will resolve the race. It's not easy to copy structs passed through interfaces in go, so I'll try this another day, but I'd be happy if someone has an idea for how to make those copies work or for a different solution.

All 6 comments

Thanks for the report, will make sure to look into it.

I don't believe that ParseSchema was intended to be called in parallel (or even more than once per application start), for what it's worth. Can you tell me more about your usecase?

I need to run it several times only in tests. Having one global (Must)?Parse call in init func wouldn't suffice, because depending on what it's being tested the resolver's dependencies need to be configured first (e.g. use a real database/email provider/payment gateway/key store/... or a mock).

Obviously this leads to redundant schema parsing, because there doesn't seem to be a way to parse once the raw GraphQL schema string/file in init (because I can't think of proper case where dynamically changing the GraphQL schema makes sense) and then pass a configured resolver to that semi-parsed schema value.

Currently I work around this by calling t.Parallel() after schema parsing.

Thanks for the additional details. I'll look into the issue 馃憤

I'm about to write tests that will trigger this behaviour and I think I can add my own global lock to work around the race for now, but I tried debugging it and I'll just post what I found out so far in case that helps.

Re-running the tests with export GORACE=history_size=7 reveals the source of the write:

Previous write at 0x00c42017db20 by goroutine 7:
  <redacted>/github.com/graph-gophers/graphql-go/internal/common.ResolveType()
      <redacted>/github.com/graph-gophers/graphql-go/internal/common/types.go:67 +0x19e
  <redacted>/github.com/graph-gophers/graphql-go/internal/schema.(*Schema).Parse()
      <redacted>/github.com/graph-gophers/graphql-go/internal/schema/schema.go:264 +0x7ec
  <redacted>/github.com/graph-gophers/graphql-go.ParseSchema()
      <redacted>/github.com/graph-gophers/graphql-go/graphql.go:36 +0x21b
  command-line-arguments_test.TestParse2()
      <redacted>/test/graphql_test.go:17 +0xb3
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:746 +0x16c

I can't make sense of this race so far. Allegedly,

        return &NonNull{OfType: ofType}, nil

(the write) is racing with

        ofType, err := ResolveType(t.OfType, resolver)

(the read) on the previous line.

(edit: I thought I found something that fixes the race but I didn't... still trying stuff now...)

By moving stuff around a bit, I found that t.OfType is racing with NonNull{OfType: ofType} but that makes no sense.

Looking at this problem again, I the root cause of the race is the sharing of Types and Directives between new schemas and the Meta schema. I suspect that copying Meta.Types and Meta.Directives in schema.New will resolve the race. It's not easy to copy structs passed through interfaces in go, so I'll try this another day, but I'd be happy if someone has an idea for how to make those copies work or for a different solution.

322 fixes this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bsr203 picture bsr203  路  6Comments

LeeWong picture LeeWong  路  4Comments

dengliu picture dengliu  路  5Comments

linuxmonk picture linuxmonk  路  3Comments

AndreasBackx picture AndreasBackx  路  4Comments