質問編集履歴
2
サンプルコードの追加
test
CHANGED
File without changes
|
test
CHANGED
@@ -151,3 +151,383 @@
|
|
151
151
|
アドバイスいただければ幸いです。
|
152
152
|
|
153
153
|
よろしくお願いいたします。
|
154
|
+
|
155
|
+
|
156
|
+
|
157
|
+
# 追記:サンプルコード
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
ご指摘を受け、実際のプログラムの挙動に似せたものをサンプルコードとして作成してみました。
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
これを作っている過程で気づいたのですが、このプログラムは**グローバル変数としてキャッシュ**を持っています。
|
166
|
+
|
167
|
+
そのキャッシュデータに対する同時アクセス制御(`mutex`)に問題があるのではないかと思い、`mutex`まわりをいくつか修正してみたところ、停止現象がかなり減った感じがしています。
|
168
|
+
|
169
|
+
そのため現時点ではグローバル変数への同時アクセスが影響しているのではないかと疑っています。
|
170
|
+
|
171
|
+
(ただし、それがF5で解消するというのもよく分からない話のように思え、この点の疑問は残っています)
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
**実際のプログラムに似せるため、プログラム内にファイルシステムへのアクセスが存在します。ご注意お願いします。**
|
178
|
+
|
179
|
+
```go
|
180
|
+
|
181
|
+
package main
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
import (
|
186
|
+
|
187
|
+
"bufio"
|
188
|
+
|
189
|
+
"encoding/json"
|
190
|
+
|
191
|
+
"io/ioutil"
|
192
|
+
|
193
|
+
"log"
|
194
|
+
|
195
|
+
"net/http"
|
196
|
+
|
197
|
+
"os"
|
198
|
+
|
199
|
+
"path"
|
200
|
+
|
201
|
+
"strconv"
|
202
|
+
|
203
|
+
"sync"
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
"github.com/gorilla/mux"
|
208
|
+
|
209
|
+
)
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
var (
|
214
|
+
|
215
|
+
DataCache = map[string]string{}
|
216
|
+
|
217
|
+
Datapath string
|
218
|
+
|
219
|
+
mutex sync.RWMutex
|
220
|
+
|
221
|
+
)
|
222
|
+
|
223
|
+
|
224
|
+
|
225
|
+
type res_ping struct {
|
226
|
+
|
227
|
+
Msg string `json:"msg"`
|
228
|
+
|
229
|
+
}
|
230
|
+
|
231
|
+
|
232
|
+
|
233
|
+
func GetPing(w http.ResponseWriter, r *http.Request) {
|
234
|
+
|
235
|
+
log.Println("GetPingStart")
|
236
|
+
|
237
|
+
defer log.Println("GetPingEnd")
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
res := res_ping{Msg: "server_alive"}
|
242
|
+
|
243
|
+
b, _ := json.Marshal(res)
|
244
|
+
|
245
|
+
w.Write(b)
|
246
|
+
|
247
|
+
}
|
248
|
+
|
249
|
+
|
250
|
+
|
251
|
+
type res_get struct {
|
252
|
+
|
253
|
+
Msg string `json:"msg"`
|
254
|
+
|
255
|
+
}
|
256
|
+
|
257
|
+
|
258
|
+
|
259
|
+
func GetData(w http.ResponseWriter, r *http.Request) {
|
260
|
+
|
261
|
+
log.Println("GetDataStart")
|
262
|
+
|
263
|
+
defer log.Println("GetDataEnd")
|
264
|
+
|
265
|
+
|
266
|
+
|
267
|
+
line, _ := mux.Vars(r)["line"]
|
268
|
+
|
269
|
+
|
270
|
+
|
271
|
+
if line == "" {
|
272
|
+
|
273
|
+
line = "0"
|
274
|
+
|
275
|
+
}
|
276
|
+
|
277
|
+
mutex.RLock()
|
278
|
+
|
279
|
+
msg := DataCache[line]
|
280
|
+
|
281
|
+
mutex.RUnlock()
|
282
|
+
|
283
|
+
|
284
|
+
|
285
|
+
res := res_get{Msg: msg}
|
286
|
+
|
287
|
+
b, _ := json.Marshal(res)
|
288
|
+
|
289
|
+
w.Write(b)
|
290
|
+
|
291
|
+
|
292
|
+
|
293
|
+
}
|
294
|
+
|
295
|
+
|
296
|
+
|
297
|
+
type req_post struct {
|
298
|
+
|
299
|
+
Data string `json:"data"`
|
300
|
+
|
301
|
+
}
|
302
|
+
|
303
|
+
|
304
|
+
|
305
|
+
type res_post struct {
|
306
|
+
|
307
|
+
Msg string `json:"msg"`
|
308
|
+
|
309
|
+
}
|
310
|
+
|
311
|
+
|
312
|
+
|
313
|
+
func PostData(w http.ResponseWriter, r *http.Request) {
|
314
|
+
|
315
|
+
log.Println("PostDataStart")
|
316
|
+
|
317
|
+
defer log.Println("PostDataEnd")
|
318
|
+
|
319
|
+
|
320
|
+
|
321
|
+
body := r.Body
|
322
|
+
|
323
|
+
defer body.Close()
|
324
|
+
|
325
|
+
b, _ := ioutil.ReadAll(body)
|
326
|
+
|
327
|
+
req := req_post{}
|
328
|
+
|
329
|
+
_ = json.Unmarshal(b, &req)
|
330
|
+
|
331
|
+
data := req.Data
|
332
|
+
|
333
|
+
|
334
|
+
|
335
|
+
mutex.Lock()
|
336
|
+
|
337
|
+
defer mutex.Unlock()
|
338
|
+
|
339
|
+
file, _ := os.OpenFile(Datapath, os.O_WRONLY|os.O_APPEND, 0666)
|
340
|
+
|
341
|
+
defer file.Close()
|
342
|
+
|
343
|
+
file.WriteString(data + "\n")
|
344
|
+
|
345
|
+
file.Close()
|
346
|
+
|
347
|
+
readdata()
|
348
|
+
|
349
|
+
|
350
|
+
|
351
|
+
res := res_post{Msg: "OK"}
|
352
|
+
|
353
|
+
rb, _ := json.Marshal(res)
|
354
|
+
|
355
|
+
w.Write(rb)
|
356
|
+
|
357
|
+
|
358
|
+
|
359
|
+
}
|
360
|
+
|
361
|
+
|
362
|
+
|
363
|
+
func SetJsonheader(w http.ResponseWriter) {
|
364
|
+
|
365
|
+
w.Header().Set("Content-Type", "application/json")
|
366
|
+
|
367
|
+
}
|
368
|
+
|
369
|
+
|
370
|
+
|
371
|
+
func Wrap(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
372
|
+
|
373
|
+
return func(w http.ResponseWriter, r *http.Request) {
|
374
|
+
|
375
|
+
EnableCors(&w)
|
376
|
+
|
377
|
+
SetJsonheader(w)
|
378
|
+
|
379
|
+
f(w, r)
|
380
|
+
|
381
|
+
}
|
382
|
+
|
383
|
+
}
|
384
|
+
|
385
|
+
|
386
|
+
|
387
|
+
func EnableCors(w *http.ResponseWriter) {
|
388
|
+
|
389
|
+
(*w).Header().Set("Access-Control-Allow-Origin", "http://localhost:8004")
|
390
|
+
|
391
|
+
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
392
|
+
|
393
|
+
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
394
|
+
|
395
|
+
}
|
396
|
+
|
397
|
+
|
398
|
+
|
399
|
+
func setup() {
|
400
|
+
|
401
|
+
log.Println(Datapath)
|
402
|
+
|
403
|
+
file, err := os.Create(Datapath)
|
404
|
+
|
405
|
+
if err != nil {
|
406
|
+
|
407
|
+
log.Fatal(err)
|
408
|
+
|
409
|
+
}
|
410
|
+
|
411
|
+
defer file.Close()
|
412
|
+
|
413
|
+
// 実際の挙動に近づけるためにファイル書き込み(データ多め)をおこなっています。問題があれば適宜修正してください。
|
414
|
+
|
415
|
+
for i := 0; i < 10000; i++ {
|
416
|
+
|
417
|
+
_, _ = file.WriteString("data898999898989898998989ddddd\n")
|
418
|
+
|
419
|
+
}
|
420
|
+
|
421
|
+
file.Close()
|
422
|
+
|
423
|
+
|
424
|
+
|
425
|
+
readdata()
|
426
|
+
|
427
|
+
//DataCache["0"] = "data0"
|
428
|
+
|
429
|
+
//DataCache["1"] = "data1"
|
430
|
+
|
431
|
+
//DataCache["2"] = "data2"
|
432
|
+
|
433
|
+
}
|
434
|
+
|
435
|
+
|
436
|
+
|
437
|
+
func readdata() {
|
438
|
+
|
439
|
+
file, _ := os.Open(Datapath)
|
440
|
+
|
441
|
+
defer file.Close()
|
442
|
+
|
443
|
+
sc := bufio.NewScanner(file)
|
444
|
+
|
445
|
+
count := 0
|
446
|
+
|
447
|
+
for sc.Scan() {
|
448
|
+
|
449
|
+
DataCache[strconv.Itoa(count)] = sc.Text()
|
450
|
+
|
451
|
+
count++
|
452
|
+
|
453
|
+
}
|
454
|
+
|
455
|
+
}
|
456
|
+
|
457
|
+
|
458
|
+
|
459
|
+
func main() {
|
460
|
+
|
461
|
+
|
462
|
+
|
463
|
+
datadir := os.TempDir()
|
464
|
+
|
465
|
+
datapath := path.Join(datadir, "data_6f3eb709jlgq0w2h.txt")
|
466
|
+
|
467
|
+
Datapath = datapath
|
468
|
+
|
469
|
+
setup()
|
470
|
+
|
471
|
+
defer os.Remove(datapath)
|
472
|
+
|
473
|
+
|
474
|
+
|
475
|
+
r := mux.NewRouter()
|
476
|
+
|
477
|
+
r.HandleFunc("/ping", Wrap(GetPing)).Methods("GET", "POST", "OPTIONS")
|
478
|
+
|
479
|
+
r.HandleFunc("/data/{line}", Wrap(GetData)).Methods("GET", "OPTIONS")
|
480
|
+
|
481
|
+
r.HandleFunc("/data", Wrap(GetData)).Methods("GET", "OPTIONS")
|
482
|
+
|
483
|
+
r.HandleFunc("/data", Wrap(PostData)).Methods("POST", "OPTIONS")
|
484
|
+
|
485
|
+
|
486
|
+
|
487
|
+
srv := http.Server{
|
488
|
+
|
489
|
+
Addr: ":48000",
|
490
|
+
|
491
|
+
Handler: r,
|
492
|
+
|
493
|
+
TLSConfig: nil,
|
494
|
+
|
495
|
+
ReadTimeout: 0,
|
496
|
+
|
497
|
+
ReadHeaderTimeout: 0,
|
498
|
+
|
499
|
+
WriteTimeout: 0,
|
500
|
+
|
501
|
+
IdleTimeout: 0,
|
502
|
+
|
503
|
+
MaxHeaderBytes: 0,
|
504
|
+
|
505
|
+
TLSNextProto: nil,
|
506
|
+
|
507
|
+
ConnState: nil,
|
508
|
+
|
509
|
+
ErrorLog: nil,
|
510
|
+
|
511
|
+
BaseContext: nil,
|
512
|
+
|
513
|
+
ConnContext: nil,
|
514
|
+
|
515
|
+
}
|
516
|
+
|
517
|
+
log.Println("start")
|
518
|
+
|
519
|
+
srv.SetKeepAlivesEnabled(false)
|
520
|
+
|
521
|
+
err := srv.ListenAndServe()
|
522
|
+
|
523
|
+
if err != nil {
|
524
|
+
|
525
|
+
log.Fatalf(err.Error())
|
526
|
+
|
527
|
+
}
|
528
|
+
|
529
|
+
}
|
530
|
+
|
531
|
+
|
532
|
+
|
533
|
+
```
|
1
fetchを使用している点を追記
test
CHANGED
File without changes
|
test
CHANGED
@@ -120,7 +120,7 @@
|
|
120
120
|
|
121
121
|
|
122
122
|
|
123
|
-
リクエストはブラウザから送る場合でも、ツール(postmanを使
|
123
|
+
リクエストはブラウザ(`fetch`を使用)から送る場合でも、ツール(`postman`を使用)で送る場合でも発生します。
|
124
124
|
|
125
125
|
発生頻度はそれなりに高く、リクエスト数十回に1回くらい見かける印象です(プロダクトでこの頻度だと使い物にならないと思います)。
|
126
126
|
|