github.com/weaviate/weaviate@v1.24.6/test/acceptance/stress_tests/stress.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package stress_tests 13 14 import ( 15 "bytes" 16 "encoding/json" 17 "fmt" 18 "io" 19 "net" 20 "net/http" 21 "strings" 22 "time" 23 24 "github.com/go-openapi/strfmt" 25 "github.com/google/uuid" 26 "github.com/pkg/errors" 27 "github.com/weaviate/weaviate/entities/models" 28 "github.com/weaviate/weaviate/entities/schema" 29 ) 30 31 // If there is already a schema present, clear it out 32 func clearExistingObjects(c *http.Client, url string) { 33 checkSchemaRequest := createRequest(url+"schema", "GET", nil) 34 checkSchemaResponseCode, body, err := performRequest(c, checkSchemaRequest) 35 if err != nil { 36 panic(errors.Wrap(err, "perform request")) 37 } 38 if checkSchemaResponseCode != 200 { 39 return 40 } 41 42 var dump models.Schema 43 if err := json.Unmarshal(body, &dump); err != nil { 44 panic(errors.Wrap(err, "Could not unmarshal read response")) 45 } 46 for _, classObj := range dump.Classes { 47 requestDelete := createRequest(url+"schema/"+classObj.Class, "DELETE", nil) 48 responseDeleteCode, _, err := performRequest(c, requestDelete) 49 if err != nil { 50 panic(errors.Wrap(err, "Could delete schema")) 51 } 52 if responseDeleteCode != 200 { 53 panic(fmt.Sprintf("Could not delete schema, code: %v", responseDeleteCode)) 54 } 55 } 56 } 57 58 func createHttpClient() *http.Client { 59 httpT := &http.Transport{ 60 Proxy: http.ProxyFromEnvironment, 61 DialContext: (&net.Dialer{ 62 Timeout: 500 * time.Second, 63 KeepAlive: 120 * time.Second, 64 }).DialContext, 65 MaxIdleConnsPerHost: 100, 66 MaxIdleConns: 100, 67 IdleConnTimeout: 90 * time.Second, 68 TLSHandshakeTimeout: 10 * time.Second, 69 ExpectContinueTimeout: 1 * time.Second, 70 } 71 return &http.Client{Transport: httpT} 72 } 73 74 // createRequest creates requests 75 func createRequest(url string, method string, payload interface{}) *http.Request { 76 var body io.Reader = nil 77 if payload != nil { 78 jsonBody, err := json.Marshal(payload) 79 if err != nil { 80 panic(errors.Wrap(err, "Could not marshal request")) 81 } 82 body = bytes.NewBuffer(jsonBody) 83 } 84 request, err := http.NewRequest(method, url, body) 85 if err != nil { 86 panic(errors.Wrap(err, "Could not create request")) 87 } 88 request.Header.Add("Content-Type", "application/json") 89 request.Header.Add("Accept", "application/json") 90 91 return request 92 } 93 94 // performRequest runs requests 95 func performRequest(c *http.Client, request *http.Request) (int, []byte, error) { 96 for { 97 response, err := c.Do(request) 98 if err != nil { 99 return 0, nil, err 100 } 101 102 body, err := io.ReadAll(response.Body) 103 response.Body.Close() 104 if err != nil { 105 return 0, nil, err 106 } 107 108 if response.StatusCode == 200 { 109 return response.StatusCode, body, nil 110 } 111 time.Sleep(time.Millisecond * 10) 112 var result map[string]interface{} 113 json.Unmarshal(body, &result) 114 message := result["error"].([]interface{})[0].(map[string]interface{})["message"].(string) 115 116 if strings.Contains(message, "concurrent transaction") { 117 time.Sleep(time.Millisecond * 10) 118 continue 119 } 120 return response.StatusCode, body, nil 121 } 122 } 123 124 func createSchemaRequest(url string, class string, multiTenantcy bool) *http.Request { 125 classObj := &models.Class{ 126 Class: class, 127 Description: "Dummy class for benchmarking purposes", 128 MultiTenancyConfig: &models.MultiTenancyConfig{ 129 Enabled: multiTenantcy, 130 }, 131 Properties: []*models.Property{ 132 { 133 DataType: []string{"int"}, 134 Description: "The value of the counter in the dataset", 135 Name: "counter", 136 }, 137 { 138 DataType: schema.DataTypeText.PropString(), 139 Tokenization: models.PropertyTokenizationWhitespace, 140 Description: "The value of the counter in the dataset", 141 Name: "name", 142 }, 143 }, 144 } 145 request := createRequest(url+"schema", "POST", classObj) 146 return request 147 } 148 149 func createObject(class string) []*models.Object { 150 objects := []*models.Object{ 151 { 152 Class: class, 153 ID: strfmt.UUID(uuid.New().String()), 154 Vector: models.C11yVector([]float32{1.0, 2, 534, 324, 0.0001}), 155 Properties: map[string]interface{}{ 156 "counter": 50, 157 "counter2": 45, 158 "something": "JustSlammedMyKeyboardahudghoig", 159 }, 160 }, 161 } 162 return objects 163 } 164 165 func createBatch(class string, batchSize int, tenants []models.Tenant) []*models.Object { 166 objects := make([]*models.Object, 0, batchSize) 167 for i := 0; i < batchSize; i++ { 168 objects = append(objects, &models.Object{ 169 Class: class, 170 ID: strfmt.UUID(uuid.New().String()), 171 Properties: map[string]interface{}{ 172 "counter": i, 173 "name": tenants[i%len(tenants)].Name, 174 }, 175 Tenant: tenants[i%len(tenants)].Name, 176 }) 177 } 178 return objects 179 }