Я пишу приложение 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, можно получить его. Надеюсь, вы, ребята, можете дать мне решение, о котором я еще не подумал.
Спасибо заранее!