diff --git a/common/app/common/configuration.scala b/common/app/common/configuration.scala index e4fca80d2eff..343498eb1d40 100644 --- a/common/app/common/configuration.scala +++ b/common/app/common/configuration.scala @@ -594,6 +594,7 @@ class GuardianConfiguration extends GuLogging { } object facia { + lazy val renderingBaseUrl = configuration.getMandatoryStringProperty("render-front.loadBalancerDnsName") lazy val stage = configuration.getStringProperty("facia.stage").getOrElse(environment.stage) lazy val collectionCap: Int = 20 } diff --git a/common/app/experiments/Experiments.scala b/common/app/experiments/Experiments.scala index c8e73e926b64..7800b7e72deb 100644 --- a/common/app/experiments/Experiments.scala +++ b/common/app/experiments/Experiments.scala @@ -89,6 +89,15 @@ object HeaderTopBarSearchCapi participationGroup = Perc1B, ) +object FrontRemoteRenderer + extends Experiment( + name = "front-remote-renderer", + description = "Renders front from fronts DCR stack", + owners = Seq(Owner.withGithub("@guardian/dotcom-platform")), + sellByDate = LocalDate.of(2023, 10, 1), + participationGroup = Perc1C, + ) + object Okta extends Experiment( name = "okta", diff --git a/common/app/renderers/DotcomRenderingService.scala b/common/app/renderers/DotcomRenderingService.scala index e291d6899908..df97616b6cb4 100644 --- a/common/app/renderers/DotcomRenderingService.scala +++ b/common/app/renderers/DotcomRenderingService.scala @@ -45,7 +45,11 @@ case class DCRLocalConnectException(message: String) extends ConnectException(me case class DCRTimeoutException(message: String) extends TimeoutException(message) case class DCRRenderingException(message: String) extends IllegalStateException(message) -class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload { +class DotcomRenderingService(overrideBaseUrl: Option[String] = None) + extends GuLogging + with ResultWithPreconnectPreload { + + private[this] val baseURL = overrideBaseUrl.getOrElse(Configuration.rendering.baseURL) private[this] val circuitBreaker = CircuitBreakerRegistry.withConfig( name = "dotcom-rendering-client", @@ -232,7 +236,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload } val json = DotcomRenderingDataModel.toJson(dataModel) - post(ws, json, Configuration.rendering.baseURL + path, page.metadata.cacheTime) + post(ws, json, baseURL + path, page.metadata.cacheTime) } def getBlocks( @@ -243,7 +247,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload val dataModel = DotcomBlocksRenderingDataModel(page, request, blocks) val json = DotcomBlocksRenderingDataModel.toJson(dataModel) - postWithoutHandler(ws, json, Configuration.rendering.baseURL + "/Blocks") + postWithoutHandler(ws, json, baseURL + "/Blocks") .flatMap(response => { if (response.status == 200) Future.successful(response.body) @@ -274,7 +278,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload ) val json = DotcomFrontsRenderingDataModel.toJson(dataModel) - post(ws, json, Configuration.rendering.baseURL + "/Front", CacheTime.Facia) + post(ws, json, baseURL + "/Front", CacheTime.Facia) } def getTagFront( @@ -289,7 +293,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload ) val json = DotcomTagFrontsRenderingDataModel.toJson(dataModel) - post(ws, json, Configuration.rendering.baseURL + "/TagFront", CacheTime.Facia) + post(ws, json, baseURL + "/TagFront", CacheTime.Facia) } def getInteractive( @@ -305,7 +309,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload // Nb. interactives have a longer timeout because some of them are very // large unfortunately. E.g. // https://www.theguardian.com/education/ng-interactive/2018/may/29/university-guide-2019-league-table-for-computer-science-information. - post(ws, json, Configuration.rendering.baseURL + "/Interactive", page.metadata.cacheTime, 4.seconds) + post(ws, json, baseURL + "/Interactive", page.metadata.cacheTime, 4.seconds) } def getAMPInteractive( @@ -317,7 +321,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload val dataModel = DotcomRenderingDataModel.forInteractive(page, blocks, request, pageType) val json = DotcomRenderingDataModel.toJson(dataModel) - post(ws, json, Configuration.rendering.baseURL + "/AMPInteractive", page.metadata.cacheTime) + post(ws, json, baseURL + "/AMPInteractive", page.metadata.cacheTime) } def getEmailNewsletters( @@ -328,7 +332,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload val dataModel = DotcomNewslettersPageRenderingDataModel.apply(page, newsletters, request) val json = DotcomNewslettersPageRenderingDataModel.toJson(dataModel) - post(ws, json, Configuration.rendering.baseURL + "/EmailNewsletters", CacheTime.Facia) + post(ws, json, baseURL + "/EmailNewsletters", CacheTime.Facia) } def getImageContent( @@ -339,7 +343,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload )(implicit request: RequestHeader): Future[Result] = { val dataModel = DotcomRenderingDataModel.forImageContent(imageContent, request, pageType, mainBlock) val json = DotcomRenderingDataModel.toJson(dataModel) - post(ws, json, Configuration.rendering.baseURL + "/Article", CacheTime.Facia) + post(ws, json, baseURL + "/Article", CacheTime.Facia) } def getMedia( @@ -351,7 +355,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload val dataModel = DotcomRenderingDataModel.forMedia(mediaPage, request, pageType, blocks) val json = DotcomRenderingDataModel.toJson(dataModel) - post(ws, json, Configuration.rendering.baseURL + "/Article", CacheTime.Facia) + post(ws, json, baseURL + "/Article", CacheTime.Facia) } def getGallery( @@ -363,7 +367,7 @@ class DotcomRenderingService extends GuLogging with ResultWithPreconnectPreload val dataModel = DotcomRenderingDataModel.forGallery(gallery, request, pageType, blocks) val json = DotcomRenderingDataModel.toJson(dataModel) - post(ws, json, Configuration.rendering.baseURL + "/Article", CacheTime.Facia) + post(ws, json, baseURL + "/Article", CacheTime.Facia) } } diff --git a/facia/app/controllers/FaciaController.scala b/facia/app/controllers/FaciaController.scala index e02a06fa4dc3..d210d1b20fca 100644 --- a/facia/app/controllers/FaciaController.scala +++ b/facia/app/controllers/FaciaController.scala @@ -27,7 +27,7 @@ import contentapi.ContentApiClient import play.api.libs.ws.WSClient import renderers.DotcomRenderingService import model.dotcomrendering.{DotcomFrontsRenderingDataModel, PageType} -import experiments.{ActiveExperiments, DeeplyRead, EuropeNetworkFront} +import experiments.{ActiveExperiments, DeeplyRead, EuropeNetworkFront, FrontRemoteRenderer} import play.api.http.ContentTypes.JSON import http.HttpPreconnections import services.dotcomrendering.{FaciaPicker, RemoteRender} @@ -46,7 +46,9 @@ trait FaciaController val ws: WSClient val mostViewedAgent: MostViewedAgent val deeplyReadAgent: DeeplyReadAgent - val remoteRenderer: DotcomRenderingService = DotcomRenderingService() + val remoteRenderer: DotcomRenderingService = new DotcomRenderingService() + val frontRemoteRenderer: DotcomRenderingService = + new DotcomRenderingService(overrideBaseUrl = Some(Configuration.facia.renderingBaseUrl)) implicit val context: ApplicationContext @@ -249,15 +251,27 @@ trait FaciaController .getOrElse("X-GU-GeoLocation", "country:row")}", ) withVaryHeader( - remoteRenderer.getFront( - ws = ws, - page = faciaPage, - pageType = pageType, - mostViewed = mostViewedAgent.mostViewed(Edition(request)), - mostCommented = mostViewedAgent.mostCommented, - mostShared = mostViewedAgent.mostShared, - deeplyRead = deeplyRead, - )(request), + if (ActiveExperiments.isParticipating(FrontRemoteRenderer)) { + frontRemoteRenderer.getFront( + ws = ws, + page = faciaPage, + pageType = pageType, + mostViewed = mostViewedAgent.mostViewed(Edition(request)), + mostCommented = mostViewedAgent.mostCommented, + mostShared = mostViewedAgent.mostShared, + deeplyRead = deeplyRead, + )(request) + } else { + remoteRenderer.getFront( + ws = ws, + page = faciaPage, + pageType = pageType, + mostViewed = mostViewedAgent.mostViewed(Edition(request)), + mostCommented = mostViewedAgent.mostCommented, + mostShared = mostViewedAgent.mostShared, + deeplyRead = deeplyRead, + )(request) + }, targetedTerritories, ) case Some((faciaPage: PressedPage, targetedTerritories)) if request.isRss =>