Я пишу приложение Go для запуска во время выполнения App Engine Go.
Я замечаю, что практически любая операция, использующая сервис App Engine (например, Datastore, Mail или даже Capabilities), требует, чтобы вы передали ему экземпляр appengine.Context
, который должен быть получен с помощью функции appengine.NewContext(req *http.Request) Context
.
Пока я пишу это приложение для App Engine, я хочу легко и быстро перенести его на какую-либо другую платформу (возможно, такую, которая не поддерживает какой-либо из API App Engine), если я этого захочу.
Итак, я абстрагирую фактическое взаимодействие с сервисами App Engine и API, написав небольшие обертки вокруг любого взаимодействия с конкретным приложением (включая функции обработки запросов). При таком подходе, если я когда-либо захочу перейти на другую платформу, я просто переписал те конкретные модули, которые привязывают мое приложение к App Engine. Легко и просто.
Единственная проблема заключается в том, что объект appengine.Context
. Я не могу передать это из моих обработчиков запросов через свои слои логики в модули, которые обрабатывают этот API, не привязывая почти весь мой код к App Engine. Я мог бы передать объект http.Request
, из которого может быть выведен объект appengine.Context
, но для этого потребуется связать вещи, которые, вероятно, не должны быть связаны. (Я считаю, что ни одна из моих приложений не может даже знать это веб-приложение, кроме тех частей, которые специально предназначены для обработки HTTP-запросов.)
Первое решение, появившееся на ум, состояло в том, чтобы просто создать постоянную переменную в каком-то модуле. Что-то вроде этого:
package context
import (
"appengine"
)
var Context appengine.Context
Затем, в обработчиках запросов, я могу установить эту переменную с помощью context.Context = appengine.NewContext(r)
и в модулях, которые непосредственно используют службы App Engine, я могу получить контекст, присоединившись к context.Context
. Ни один из промежуточных кодов не должен знать о существовании объекта appengine.Context
. Единственная проблема заключается в том, что "несколько запросов могут обрабатываться одновременно с данным экземпляром" , что может привести к условиям гонки и неожиданному поведению с этим планом. (Один запрос устанавливает его, другой устанавливает его, первый обращается к нему и получает неправильный объект appengine.Context
.)
Я мог бы теоретически хранить appengine.Context
в хранилище данных, но тогда мне пришлось бы передавать определенный идентификатор запроса по логическим слоям в модули, специфичные для службы, определяющие, какой объект appengine.Context
в хранилище данных является тем, который текущий запрос, который снова соединит вещи, которые, как я думаю, не должен сочетаться. (И это увеличит использование хранилища данных приложения.)
Я мог бы также передать объект appengine.Context
по всей логической цепочке с типом interface{}
весь путь и иметь любой модуль, который не нуждается в объекте appengine.Context
, игнорировать его. Это позволит избежать привязки большей части моего приложения к чему-либо конкретному. Однако это также кажется очень беспорядочным.
Итак, я немного пораньше, как для чистого обеспечения модулей App-Engine, которые нуждаются в объекте appengine.Context
, можно получить его. Надеюсь, вы, ребята, можете дать мне решение, о котором я еще не подумал.
Спасибо заранее!