How to autowire 2 symfony services, which use the same interface and addtional arguments - yaml

I have two services, which both use the same interface and one is injected in the other.
With this configuration in the service.yaml everything worked well:
# fix autowiring for 2 services using the same interface
App\Domain\ListService: ~
App\Domain\SapService\SapListService: ~
App\Domain\ListService $sapListService: '#App\Domain\SapService\SapListService'
App\Domain\ListServiceInterface: '#App\Domain\ListService'
following the official documentation found here.
Now one of my services needs the information in which environment the class is currently running.
In a simple service configuration I would write it like this:
App\Service\FooService:
arguments:
$env: '%env(APP_ENV)%'
But how do I add the environment information in my more complex situation?
I tried this:
App\Domain\ListService: ~
App\Domain\SapService\SapListService: ~
App\Domain\ListService $sapListService: '#App\Domain\SapService\SapListService'
arguments:
$env: '%env(APP_ENV)%'
App\Domain\ListServiceInterface: '#App\Domain\ListService'
which throws this error:
The file "/var/www/src/../config/services.yaml" does not contain valid YAML: Unable to parse at line 52 (near " arguments:").
What is the proper formatting to parse the environment information into my service?
I tried manual wiring like this:
public function __construct(
ListServiceInterface $sapListService,
#[Autowire('%env(APP_ENV)%')]
string $env
) {
$this->sapListService = $sapListService;
$this->env = $env;
}
which gives me the error:
In DefinitionErrorExceptionPass.php line 54:
Cannot autowire service "App\Domain\ListService": argument "$env" of method "__construct()" is type-hinted "string", you should configure its
value explicitly.
Looks like the Autowire annotation is only available with symfony 6

You should use the namespace in the redis config to separate the different environments and not use the APP_ENV var to create the keys to store.

I guess the best solution is to prefix the cache key with the environment via the cache configuration in the cache.yaml file.
The solution is described here

Related

Facing problem to set service name from env variable in serverless.yml file after upgrading to latest version

I am trying to set the serverless service name from the env file. Before deploying serverless, I have set the value of ECR_NAME as
export ECR_NAME=$(echo $CI_ENVIRONMENT_SLUG | awk -v srch="-" -v repl="" '{ gsub(srch,repl,$0); print $0 }')
Then I have written it as below in the serverless.yml.
service: ${env:CI_PROJECT_NAME}-${env:ECR_NAME}
useDotenv: true
configValidationMode: error
variablesResolutionMode: 20210326
Getting the below error:
Error:
Cannot resolve serverless.yml: "service" property is not accessible (configured behind variables which cannot be resolved at this stage)
Installed version
Framework Core: 3.14.0
Plugin: 6.2.1
SDK: 4.3.2
See Issue #9313 on GitHub:
https://github.com/serverless/serverless/issues/9813
Problem:
The latest version of the serverless framework is no longer working
for AWS Lambda deployments and is throwing the following error:
Cannot resolve serverless.yml: “provider.stage” property is not accessible (configured behind variables which cannot be resolved at this stage)
Discussion:
with the new resolver, such definition is not supported. In general,
it is discouraged to configure stage behind env variables for example,
as at the point where stage is going to be resolved, not whole env
might be available (e.g. loading env vars from .env.{stage} needs to
resolve stage first in order to properly load variables from file),
which might introduce bugs that are hard to debug. Also, the
provider.stage serves more as a "default" stage and --stage flag via
CLI is the preferred way of setting it.
...
In your configuration file you explicitly opt-in to use new resolver
via variablesResolutionMode: 20210326 variable.
We are not discouraging the use of env variables - quite the contrary,
we've been promoting them as a replacement for custom CLI options for
example and it is generally a great practice to use them. As for env
source for stage specifically, this has been introduced as a fix, as
stage should be already resolved before we attempt env variables
resolution, as loading .env files can depend on stage property.
#medikoo I know we've talked about it today, do you think it could be
safe to resolve stage from env source in specific circumstances (e.g.
when dotenv is not used)?
See also:
https://www.serverless.com/framework/docs/deprecations/#new-variables-resolver
https://www.serverless.com/framework/docs/providers/aws/guide/variables/

MICRONAUT_FUNCTION_NAME Environment variables is not working in AWS lambda

I want to write multiple function inside our app so instead of putting config in application.yml I use MICRONAUT_FUNCTION_NAME environment variable in AWS lambda but I keep receiving the error
No function found for name: xxx: java.lang.IllegalStateException
java.lang.IllegalStateException: No function found for name: xxx
at io.micronaut.function.executor.AbstractExecutor.lambda$resolveFunction$0(AbstractExecutor.java:60)
at java.util.Optional.orElseThrow(Optional.java:290)
at io.micronaut.function.executor.AbstractExecutor.resolveFunction(AbstractExecutor.java:60)
at io.micronaut.function.executor.StreamFunctionExecutor.execute(StreamFunctionExecutor.java:89)
at io.micronaut.function.aws.MicronautRequestStreamHandler.handleRequest(MicronautRequestStreamHandler.java:54)
Do anyone know what did I miss or it's not possible for multiple functions?
You can use io.micronaut:micronaut-function-aws:1.4.0 with micronaut version 1.3.3.
This happens because I use Micronaut version 1.3.3. If I downgrade to 1.2.11, it works perfectly.

Spring Boot - SpEL - Check List Contains - #ConditionalOnExpression

Given that I have the following properties:
values[0]=A
values[1]=B
values[2]=C
I need to check that values contains A in a #ConditionalOnExpression annotation. As of yet, I have not found an example of how to do it. I have tried this, but it does not work:
#ConditionalOnExpression("${values}.contains('A')")
It results in:
java.lang.IllegalStateException: Failed to load ApplicationContext
You need $ expresion surrounded by single quotes
#ConditionalOnExpression("'${values}'.contains('A')")

Spring Boot Yarn - Passing Command line arguments

i'm trying to pass command line arguments in my Spring Boot Yarn application and am having difficulties. i understand that i can set these in the yml document spring.yarn.appmaster.launchcontext.arguments but how can it from the command line? like java -jar MyYarnApp.jar {arg0} {arg1} and get access to it from my #YarnContainer?
i've discovered that #YarnProperties maps to spring.yarn.appmaster.launchcontext.arguments but i want to set them from the command line, not in the yml
You are pretty close on this when you found spring.yarn.client.launchcontext.arguments and spring.yarn.appmaster.launchcontext.arguments. We don't have settings which would automatically pass all command-line arguments from a client into an appmaster which would then pass them into a container launch context. Not sure if we even want to do that because you surely want to be on control what happens with YARN container launch context. User using a client could then potentially pass a rogue arguments along a food chain.
Having said that, lets see what we can do with our Simple Single Project YARN Application Guide.
We still need to use those launch context arguments to define our command line parameters to basically map how things are passed from a client into an appmaster into a container.
What I added in application.yml:
spring:
yarn:
client:
launchcontext:
arguments:
--my.appmaster.arg1: ${my.client.arg1:notset1}
appmaster:
launchcontext:
arguments:
--my.container.arg1: ${my.appmaster.arg1:notset2}
Modified HelloPojo in Application class:
#YarnComponent
#Profile("container")
public static class HelloPojo {
private static final Log log = LogFactory.getLog(HelloPojo.class);
#Autowired
private Configuration configuration;
#Value("${my.container.arg1}")
private String arg1;
#OnContainerStart
public void onStart() throws Exception {
log.info("Hello from HelloPojo");
log.info("Container arg1 value is " + arg1);
log.info("About to list from hdfs root content");
FsShell shell = new FsShell(configuration);
for (FileStatus s : shell.ls(false, "/")) {
log.info(s);
}
shell.close();
}
}
Notice how I added arg1 and used #Value to map it with my.container.arg1. We can either use #ConfigurationProperties or #Value which are normal Spring and Spring Boot functionalities and there's more in Boot's reference docs how to use those.
You could then modify AppIT unit test:
ApplicationInfo info = submitApplicationAndWait(Application.class, new String[]{"--my.client.arg1=arg1value"});
and run build with tests
./gradlew clean build
or just build it without running test:
./gradlew clean build -x test
and then submit into a real hadoop cluster with your my.client.arg1.
java -jar build/libs/gs-yarn-basic-single-0.1.0.jar --my.client.arg1=arg1value
Either way you see arg1value logged in container logs:
[2014-07-18 08:49:09.802] boot - 2003 INFO [main] --- ContainerLauncherRunner: Running YarnContainer with parameters [--spring.profiles.active=container,--my.container.arg1=arg1value]
[2014-07-18 08:49:09.806] boot - 2003 INFO [main] --- Application$HelloPojo: Container arg1 value is arg1value
Using format ${my.client.arg1:notset1} also allows you to automatically define a default value notset1 if my.client.arg1 is omitted by user. We're working on Spring Application Context here orchestrated by Spring Boot so all the goodies from there are in your disposal
If you need more precise control of those user facing arguments(using args4j, jopt, etc) then you'd need to have a separate code/jar for client/appmaster/container order to create a custom client main method. All the other Spring YARN getting started guides are pretty much using multi-project builds so look at those. For example if you just want to have first and second argument value without having a need to use full --my.client.arg1=arg1value on a command line.
Let us know if this works for you and if you have any other ideas to make things simpler.

Changing cache_dir and log_dir with Symfony2

Because of deployment constraints, I would like to have the log and cache directories used by my Symfony2 application somewhere under /var/... in my file system. For this reason, I am looking for a way to configure Symfony and to override the default location for these two directories.
I have seen the kernel.cache_dir and kernel.log_dir and read the class Kernel.php. From what I have seen, I don't think that it is possible to change the dir locations by configuration and I would have to patch the Kernel.php class.
Is that true, or is there a way to achieve what I want without modifying the framework code?
Add the following methods to app/AppKernel.php (AppKernel extends Kernel) making them return your preferred paths:
public function getCacheDir()
{
return $this->rootDir . '/my_cache/' . $this->environment;
}
public function getLogDir()
{
return $this->rootDir . '/my_logs';
}
I was happy to find your post, but I was a little bit confused of the unhelping answers.
I got the same problem and found out that the logs are depending on the config parameter
kernel.logs_dir.
So I just added it to my config.yml parameters:
kernel.logs_dir: /var/log/symfonyLogs
I hope it will helpfull for you even, if its a late answer.
i think the easiest way is to link the folder to another place. We have made this on the prod server but when you develop local perhaps on windows its a bit complicated to set the symlinks.
ln -s /var/cache/ /var/www/project/app/cache
something like this.
I would like to offer an alternative and that is to set environment variables to change these directories. This way it's easier to set depending on the stage. (testing, production or development)
export SYMFONY__KERNEL__CACHE_DIR "/your/directory/cache"
export SYMFONY__KERNEL__LOGS_DIR "/your/directory/logs"
Environment variables can also be set in the virtual host with SetEnv.
When reading kernel parameters symfony will look for all the $_SERVER variables that start with SYMFONY__, strip the first part and convert all the double underscores into a .
Source code
See line 568 to 608
In symfony you can override the cache (and logs) directory by extending the method in AppKernel.
// app/appKernel.php
class AppKernel extends Kernel
{
// ...
public function getCacheDir()
{
return $this->rootDir.'/'.$this->environment.'/cache';
}
}
Check out http://symfony.com/doc/current/cookbook/configuration/override_dir_structure.html#override-cache-dir
I used the configuration solution from Dragnic but I put the paths in the parameters.yml file because this file is ignored by git. in other words, it's not synchronized from my PC to the git repository so there is no impact in the prod environment.
# app/config/parameters.yml
parameters:
database_driver: pdo_mysql
[...]
kernel.cache_dir: "T:/project/cache"
kernel.logs_dir: "T:/project/logs"
Configuration: Windows7, WAMP 2.4 and Symfony 2.3.20.
But you have to know that:
Overwriting the kernel.cache_dir parameter from your config file is a very bad idea, and not a supported way to change the cache folder in Symfony.
It breaks things because you would now have different cache folders for the kernel Kernel::getCacheDir() and for the parameter.
Source: https://github.com/symfony/AsseticBundle/issues/370
So you should use it only in dev environment and if you don't want to change the content of the app/AppKernel.php file, otherwise see the other answers.
No accepted answer, and a really old question, but I found it with google, so I post here a more recent way to change the cache directory, and the logs directory, (source here)
remember, short syntax for arrays require php 5.4
you can select the env to modify, and manage different cache and logs directories if you want
public function getCacheDir()
{
if (in_array($this->environment, ['prod', 'test'])) {
return '/tmp/cache/' . $this->environment;
}
return parent::getCacheDir();
}
public function getLogDir()
{
if (in_array($this->environment, ['prod', 'test'])) {
return '/var/log/symfony/logs';
}
return parent::getLogDir();
}

Resources